diff --git a/src/common/resources/lang/en_US/gui.lang b/src/common/resources/lang/en_US/gui.lang
index 97fd15cfb..3c4dd0830 100644
--- a/src/common/resources/lang/en_US/gui.lang
+++ b/src/common/resources/lang/en_US/gui.lang
@@ -206,6 +206,11 @@ gui.options.page.language_packs.title=Language Packs
 gui.options.page.language_packs.category.language_packs=Language Packs
 gui.options.page.language_packs.button.open_folder=Open Folder
 
+gui.options.page.debug.title=Debug Menu
+gui.options.page.debug.button.open.model_viewer=Open Model Viewer
+gui.options.page.debug.button.open.biome_finder=Open Biome Finder
+gui.options.page.debug.button.open.datadumper=Run Data Dumper
+
 gui.options.page.search.title=Search
 
 gui.photo_mode.label.mouse_hint=Click and drag to move and rotate.
@@ -282,3 +287,43 @@ gui.trommel.label.inventory=Inventory
 gui.hud_designer.button.done=Done
 
 gui.pick_monster.label.title=Select mob to spawn
+
+gui.model_viewer.slider.variant=Variant: %d
+gui.model_viewer.slider.meta=Meta: %d
+gui.model_viewer.button.tickprogress=Run Tick: %s
+gui.model_viewer.button.rotate=Rotate Labels: %s
+gui.model_viewer.button.reload_textures=Reload Textures
+
+gui.model_viewer.button.category=Category
+
+model.category.entity.info=Entity: %s
+model.category.entity.name=Entity
+model.category.entity.tnt.slider.fuse=Fuse: %d
+model.category.entity.sheep.slider.color=Color: %s
+model.category.entity.painting.slider.motif=Painting: %s
+model.category.entity.fireflycluster.slider.size=Size: %d
+model.category.entity.fireflycluster.button.cycle=Color: %s
+model.category.entity.item.button.cycle=Cycle Item
+model.category.entity.item.slider.size=Size: %d
+model.category.entity.sand.button.cycle=Cycle Block
+model.category.entity.creeper.button.charged=Charged: %s
+model.category.entity.armored_zombie.button.sword=Sword: %s
+model.category.entity.wolf.button.tamed=Tamed: %s
+model.category.entity.wolf.button.sitting=Sitting: %s
+model.category.entity.wolf.button.angry=Angry: %s
+model.category.entity.wolf.button.armor=Armor: %s
+model.category.entity.wolf.button.item=Item: %s
+model.category.entity.boat.button.flag=Flag: %s
+model.category.entity.boat.button.wind=Wind: %s degrees
+model.category.entity.slime.slider.size=Slime: %s
+model.category.entity.minecart.button.cycle=Cycle Minecart
+
+model.category.block.name=Block
+model.category.block.info=Block: %s
+model.category.block.basket.slider.fill=Fill: %s
+model.category.block.spawner.button.id=Mob: %s
+
+model.category.particle.name=Particle
+model.category.particle.info=Particle: %s
+model.category.particle.radius.slider=Radius: %s
+model.category.particle.note.slider=Note: %s
\ No newline at end of file
diff --git a/src/common/resources/lang/en_US/item.lang b/src/common/resources/lang/en_US/item.lang
index ddaaf49d2..e66e80d74 100644
--- a/src/common/resources/lang/en_US/item.lang
+++ b/src/common/resources/lang/en_US/item.lang
@@ -286,6 +286,8 @@ item.dust.sugar.name=Sugar
 item.dust.sugar.desc=Can craft sweet treats.
 item.food.cake.name=Cake
 item.food.cake.desc=Not a lie!
+item.food.pumpkin_pie.name=Pumpkin Pie
+item.food.pumpkin_pie.desc=Thanks!
 item.bed.name=Bed
 item.bed.desc=Take a nap overnight.
 item.repeater.name=Redstone Repeater
diff --git a/src/common/resources/lang/en_US/options.lang b/src/common/resources/lang/en_US/options.lang
index 9da21c214..1217a7a19 100644
--- a/src/common/resources/lang/en_US/options.lang
+++ b/src/common/resources/lang/en_US/options.lang
@@ -141,6 +141,10 @@ options.flightSmoothness=Flight Smoothness
 options.customAnimations=Custom Animations
 options.turnWithVehicle=Turn with Vehicle
 options.playServerSounds=Play Server Sounds
+options.lightmapStyle=Lightmap Style
+options.lightmapStyle.default=Default
+options.lightmapStyle.cosy=Cosy
+options.lightmapStyle.disabled=Disabled
 
 options.tooltipStyle.default=Default
 options.tooltipStyle.modern=Modern
diff --git a/src/common/resources/lang/en_US/tile.lang b/src/common/resources/lang/en_US/tile.lang
index fa7dd13e6..013b7217b 100644
--- a/src/common/resources/lang/en_US/tile.lang
+++ b/src/common/resources/lang/en_US/tile.lang
@@ -1 +1 @@
-tile.stone.name=Stone
tile.stone.desc=A block of solid stone.
tile.basalt.name=Basalt
tile.basalt.desc=A block of solid basalt.
tile.limestone.name=Limestone
tile.limestone.desc=A block of solid limestone.
tile.granite.name=Granite
tile.granite.desc=A block of solid granite.
tile.marble.name=Marble
tile.marble.desc=A block of solid marble.
tile.slate.name=Slate
tile.slate.desc=A block of solid slate.
tile.permafrost.name=Permafrost
tile.permafrost.desc=A block of frozen stone.

tile.cobble.stone.name=Cobblestone
tile.cobble.stone.desc=Stone, smashed apart and reconstituted.
tile.cobble.stone.mossy.name=Mossy Cobblestone
tile.cobble.stone.mossy.desc=Cobblestone with added greenery.
tile.cobble.basalt.name=Cobbled Basalt
tile.cobble.basalt.desc=Basalt, smashed apart and reconstituted.
tile.cobble.limestone.name=Cobbled Limestone
tile.cobble.limestone.desc=Limestone, smashed apart and reconstituted.
tile.cobble.granite.name=Cobbled Granite
tile.cobble.granite.desc=Granite, smashed apart and reconstituted.
tile.cobble.permafrost.name=Cobbled Permafrost
tile.cobble.permafrost.desc=Permafrost, smashed apart and reconstituted.

tile.pillar.marble.name=Marble Pillar
tile.pillar.marble.desc=A block of marble engraved into a pillar.
tile.capstone.marble.name=Marble Capstone
tile.capstone.marble.desc=A pillar capstone made of solid marble.

tile.sandstone.name=Sandstone
tile.sandstone.desc=Compacted sand.

tile.stone.carved.name=Carved Stone
tile.stone.carved.desc=Polished Stone with lines hewn through the middle.
tile.granite.carved.name=Carved Granite
tile.granite.carved.desc=Polished Granite with lines hewn through the middle.
tile.limestone.carved.name=Carved Limestone
tile.limestone.carved.desc=Polished Limestone with lines hewn through the middle.
tile.basalt.carved.name=Carved Basalt
tile.basalt.carved.desc=Polished Basalt with lines hewn through the middle.

tile.planks.oak.name=Wooden Planks
tile.planks.oak.desc=Processed tree insides.
tile.planks.oak.painted.name=Mystery Planks
tile.planks.oak.painted.desc=How did you get this?!
tile.planks.oak.painted.black.name=Black Wooden Planks
tile.planks.oak.painted.black.desc=Wooden planks, stained black.
tile.planks.oak.painted.red.name=Red Wooden Planks
tile.planks.oak.painted.red.desc=Wooden planks, stained red.
tile.planks.oak.painted.green.name=Green Wooden Planks
tile.planks.oak.painted.green.desc=Wooden planks, stained green.
tile.planks.oak.painted.brown.name=Brown Wooden Planks
tile.planks.oak.painted.brown.desc=Wooden planks, stained brown.
tile.planks.oak.painted.blue.name=Blue Wooden Planks
tile.planks.oak.painted.blue.desc=Wooden planks, stained blue.
tile.planks.oak.painted.purple.name=Purple Wooden Planks
tile.planks.oak.painted.purple.desc=Wooden planks, stained purple.
tile.planks.oak.painted.cyan.name=Cyan Wooden Planks
tile.planks.oak.painted.cyan.desc=Wooden planks, stained cyan.
tile.planks.oak.painted.silver.name=Light Gray Wooden Planks
tile.planks.oak.painted.silver.desc=Wooden planks, stained light gray.
tile.planks.oak.painted.gray.name=Gray Wooden Planks
tile.planks.oak.painted.gray.desc=Wooden planks, stained gray.
tile.planks.oak.painted.pink.name=Pink Wooden Planks
tile.planks.oak.painted.pink.desc=Wooden planks, stained pink.
tile.planks.oak.painted.lime.name=Lime Wooden Planks
tile.planks.oak.painted.lime.desc=Wooden planks, stained lime.
tile.planks.oak.painted.yellow.name=Yellow Wooden Planks
tile.planks.oak.painted.yellow.desc=Wooden planks, stained yellow.
tile.planks.oak.painted.lightblue.name=Light Blue Wooden Planks
tile.planks.oak.painted.lightblue.desc=Wooden planks, stained light blue.
tile.planks.oak.painted.magenta.name=Magenta Wooden Planks
tile.planks.oak.painted.magenta.desc=Wooden planks, stained magenta.
tile.planks.oak.painted.orange.name=Orange Wooden Planks
tile.planks.oak.painted.orange.desc=Wooden planks, stained orange.
tile.planks.oak.painted.white.name=White Wooden Planks
tile.planks.oak.painted.white.desc=Wooden planks, stained white.

tile.torch.coal.name=Torch
tile.torch.coal.desc=Helps light the way.

tile.ladder.oak.name=Oak Ladder
tile.ladder.oak.desc=For very rapid vertical movement.

tile.fence.planks.oak.name=Oak Fence
tile.fence.planks.oak.desc=Too tall to jump over.

tile.fence.planks.oak.painted.name=Mystery Wooden Fence
tile.fence.planks.oak.painted.desc=How did you get this?!
tile.fence.planks.oak.painted.black.name=Black Wooden Fence
tile.fence.planks.oak.painted.black.desc=A wooden fence, stained black.
tile.fence.planks.oak.painted.red.name=Red Wooden Fence
tile.fence.planks.oak.painted.red.desc=A wooden fence, stained red.
tile.fence.planks.oak.painted.green.name=Green Wooden Fence
tile.fence.planks.oak.painted.green.desc=A wooden fence, stained green.
tile.fence.planks.oak.painted.brown.name=Brown Wooden Fence
tile.fence.planks.oak.painted.brown.desc=A wooden fence, stained brown.
tile.fence.planks.oak.painted.blue.name=Blue Wooden Fence
tile.fence.planks.oak.painted.blue.desc=A wooden fence, stained blue.
tile.fence.planks.oak.painted.purple.name=Purple Wooden Fence
tile.fence.planks.oak.painted.purple.desc=A wooden fence, stained purple.
tile.fence.planks.oak.painted.cyan.name=Cyan Wooden Fence
tile.fence.planks.oak.painted.cyan.desc=A wooden fence, stained cyan.
tile.fence.planks.oak.painted.silver.name=Light Gray Wooden Fence
tile.fence.planks.oak.painted.silver.desc=A wooden fence, stained light gray.
tile.fence.planks.oak.painted.gray.name=Gray Wooden Fence
tile.fence.planks.oak.painted.gray.desc=A wooden fence, stained gray.
tile.fence.planks.oak.painted.pink.name=Pink Wooden Fence
tile.fence.planks.oak.painted.pink.desc=A wooden fence, stained pink.
tile.fence.planks.oak.painted.lime.name=Lime Wooden Fence
tile.fence.planks.oak.painted.lime.desc=A wooden fence, stained lime.
tile.fence.planks.oak.painted.yellow.name=Yellow Wooden Fence
tile.fence.planks.oak.painted.yellow.desc=A wooden fence, stained yellow.
tile.fence.planks.oak.painted.lightblue.name=Light Blue Wooden Fence
tile.fence.planks.oak.painted.lightblue.desc=A wooden fence, stained light blue.
tile.fence.planks.oak.painted.magenta.name=Magenta Wooden Fence
tile.fence.planks.oak.painted.magenta.desc=A wooden fence, stained magenta.
tile.fence.planks.oak.painted.orange.name=Orange Wooden Fence
tile.fence.planks.oak.painted.orange.desc=A wooden fence, stained orange.
tile.fence.planks.oak.painted.white.name=White Wooden Fence
tile.fence.planks.oak.painted.white.desc=A wooden fence, stained white.

tile.fencegate.planks.oak.name=Wooden Fence Gate
tile.fencegate.planks.oak.desc=Like a door but for fences.

tile.fencegate.planks.oak.painted.name=Mystery Wooden Fence Gate
tile.fencegate.planks.oak.painted.desc=How did you get this?!
tile.fencegate.planks.oak.painted.black.name=Black Wooden Fence Gate
tile.fencegate.planks.oak.painted.black.desc=A wooden fence gate, stained black.
tile.fencegate.planks.oak.painted.red.name=Red Wooden Fence Gate
tile.fencegate.planks.oak.painted.red.desc=A wooden fence gate, stained red.
tile.fencegate.planks.oak.painted.green.name=Green Wooden Fence Gate
tile.fencegate.planks.oak.painted.green.desc=A wooden fence gate, stained green.
tile.fencegate.planks.oak.painted.brown.name=Brown Wooden Fence Gate
tile.fencegate.planks.oak.painted.brown.desc=A wooden fence gate, stained brown.
tile.fencegate.planks.oak.painted.blue.name=Blue Wooden Fence Gate
tile.fencegate.planks.oak.painted.blue.desc=A wooden fence gate, stained blue.
tile.fencegate.planks.oak.painted.purple.name=Purple Wooden Fence Gate
tile.fencegate.planks.oak.painted.purple.desc=A wooden fence gate, stained purple.
tile.fencegate.planks.oak.painted.cyan.name=Cyan Wooden Fence Gate
tile.fencegate.planks.oak.painted.cyan.desc=A wooden fence gate, stained cyan.
tile.fencegate.planks.oak.painted.silver.name=Light Gray Wooden Fence Gate
tile.fencegate.planks.oak.painted.silver.desc=A wooden fence gate, stained light gray.
tile.fencegate.planks.oak.painted.gray.name=Gray Wooden Fence Gate
tile.fencegate.planks.oak.painted.gray.desc=A wooden fence gate, stained gray.
tile.fencegate.planks.oak.painted.pink.name=Pink Wooden Fence Gate
tile.fencegate.planks.oak.painted.pink.desc=A wooden fence gate, stained pink.
tile.fencegate.planks.oak.painted.lime.name=Lime Wooden Fence Gate
tile.fencegate.planks.oak.painted.lime.desc=A wooden fence gate, stained lime.
tile.fencegate.planks.oak.painted.yellow.name=Yellow Wooden Fence Gate
tile.fencegate.planks.oak.painted.yellow.desc=A wooden fence gate, stained yellow.
tile.fencegate.planks.oak.painted.lightblue.name=Light Blue Wooden Fence Gate
tile.fencegate.planks.oak.painted.lightblue.desc=A wooden fence gate, stained light blue.
tile.fencegate.planks.oak.painted.magenta.name=Magenta Wooden Fence Gate
tile.fencegate.planks.oak.painted.magenta.desc=A wooden fence gate, stained magenta.
tile.fencegate.planks.oak.painted.orange.name=Orange Wooden Fence Gate
tile.fencegate.planks.oak.painted.orange.desc=A wooden fence gate, stained orange.
tile.fencegate.planks.oak.painted.white.name=White Wooden Fence Gate
tile.fencegate.planks.oak.painted.white.desc=A wooden fence gate, stained white.

tile.bookshelf.planks.oak.name=Bookshelf
tile.bookshelf.planks.oak.desc=A repository of knowledge.

tile.wool.name=Wool
tile.wool.desc=How did you get this?!
tile.wool.black.name=Black Wool
tile.wool.black.desc=Sheep's wool, dyed black.
tile.wool.red.name=Red Wool
tile.wool.red.desc=Sheep's wool, dyed red.
tile.wool.green.name=Green Wool
tile.wool.green.desc=Sheep's wool, dyed green.
tile.wool.brown.name=Brown Wool
tile.wool.brown.desc=Sheep's wool, dyed brown.
tile.wool.blue.name=Blue Wool
tile.wool.blue.desc=Sheep's wool, dyed blue.
tile.wool.purple.name=Purple Wool
tile.wool.purple.desc=Sheep's wool, dyed purple.
tile.wool.cyan.name=Cyan Wool
tile.wool.cyan.desc=Sheep's wool, dyed cyan.
tile.wool.silver.name=Light Gray Wool
tile.wool.silver.desc=Sheep's wool, dyed light gray.
tile.wool.gray.name=Gray Wool
tile.wool.gray.desc=Sheep's wool, dyed gray.
tile.wool.pink.name=Pink Wool
tile.wool.pink.desc=Sheep's wool, dyed pink.
tile.wool.lime.name=Lime Wool
tile.wool.lime.desc=Sheep's wool, dyed lime.
tile.wool.yellow.name=Yellow Wool
tile.wool.yellow.desc=Sheep's wool, dyed yellow.
tile.wool.lightblue.name=Light Blue Wool
tile.wool.lightblue.desc=Sheep's wool, dyed light blue.
tile.wool.magenta.name=Magenta Wool
tile.wool.magenta.desc=Sheep's wool, dyed magenta.
tile.wool.orange.name=Orange Wool
tile.wool.orange.desc=Sheep's wool, dyed orange.
tile.wool.white.name=White Wool
tile.wool.white.desc=Sheep's wool, dyed white.

tile.brick.clay.name=Clay Bricks
tile.brick.clay.desc=Stacked bricks of baked clay.
tile.brick.stone.polished.name=Polished Stone Bricks
tile.brick.stone.polished.desc=Stacked bricks of polished stone.
tile.brick.stone.polished.mossy.name=Mossy Polished Stone Bricks
tile.brick.stone.polished.mossy.desc=Stacked bricks of polished stone with added greenery.
tile.brick.sandstone.name=Sandstone Bricks
tile.brick.sandstone.desc=Stacked bricks of sandstone.
tile.brick.gold.name=Gold Bricks
tile.brick.gold.desc=Stacked bricks of gold.
tile.brick.lapis.name=Lapis Lazuli Bricks
tile.brick.lapis.desc=Stacked bricks of lapis lazuli.
tile.brick.basalt.name=Basalt Bricks
tile.brick.basalt.desc=Stacked bricks of basalt.
tile.brick.limestone.name=Limestone Bricks
tile.brick.limestone.desc=Stacked bricks of limestone.
tile.brick.granite.name=Granite Bricks
tile.brick.granite.desc=Stacked bricks of granite.
tile.brick.marble.name=Marble Bricks
tile.brick.marble.desc=Stacked bricks of marble.
tile.brick.slate.name=Slate Bricks
tile.brick.slate.desc=Stacked bricks of slate.
tile.brick.stone.name=Stone Bricks
tile.brick.stone.desc=Stacked bricks of stone.
tile.brick.permafrost.name=Permafrost Bricks
tile.brick.permafrost.desc=Stacked bricks of permafrost.
tile.brick.iron.name=Iron Bricks
tile.brick.iron.desc=Stacked bricks of iron.

tile.slab.planks.oak.name=Wooden Slab
tile.slab.planks.oak.desc=A slab of wooden planks.
tile.slab.cobble.stone.name=Cobblestone Slab
tile.slab.cobble.stone.desc=A slab of cobblestone.
tile.slab.sandstone.name=Sandstone Slab
tile.slab.sandstone.desc=A slab of sandstone.
tile.slab.brick.stone.polished.name=Polished Stone Brick Slab
tile.slab.brick.stone.polished.desc=A slab of polished stone bricks.
tile.slab.stone.carved.name=Polished Stone Slab
tile.slab.stone.carved.desc=A slab of polished stone.
tile.slab.brick.marble.name=Marble Brick Slab
tile.slab.brick.marble.desc=A slab of marble bricks.
tile.slab.brick.clay.name=Clay Brick Slab
tile.slab.brick.clay.desc=A slab of clay bricks.
tile.slab.capstone.marble.name=Marble Capstone Slab
tile.slab.capstone.marble.desc=Marble sculpted into a capstone.
tile.slab.cobble.basalt.name=Cobbled Basalt Slab
tile.slab.cobble.basalt.desc=A slab of cobbled basalt.
tile.slab.cobble.limestone.name=Cobbled Limestone Slab
tile.slab.cobble.limestone.desc=A slab of cobbled limestone.
tile.slab.cobble.granite.name=Cobbled Granite Slab
tile.slab.cobble.granite.desc=A slab of cobbled granite.
tile.slab.brick.basalt.name=Basalt Brick Slab
tile.slab.brick.basalt.desc=A slab of basalt bricks.
tile.slab.brick.limestone.name=Limestone Brick Slab
tile.slab.brick.limestone.desc=A slab of limestone bricks.
tile.slab.brick.granite.name=Granite Brick Slab
tile.slab.brick.granite.desc=A slab of granite bricks.
tile.slab.brick.slate.name=Slate Brick Slab
tile.slab.brick.slate.desc=A slab of slate bricks.
tile.slab.brick.stone.name=Stone Brick Slab
tile.slab.brick.stone.desc=A slab of stone bricks.
tile.slab.granite.carved.name=Polished Granite Slab
tile.slab.granite.carved.desc=A slab of polished granite.
tile.slab.limestone.carved.name=Polished Limestone Slab
tile.slab.limestone.carved.desc=A slab of polished limestone.
tile.slab.basalt.carved.name=Polished Basalt Slab
tile.slab.basalt.carved.desc=A slab of polished basalt.

tile.slab.planks.oak.painted.name=Mystery Wooden Slab
tile.slab.planks.oak.painted.desc=How did you get this?!
tile.slab.planks.oak.painted.black.name=Black Wooden Slab
tile.slab.planks.oak.painted.black.desc=A slab of wooden planks, stained black.
tile.slab.planks.oak.painted.red.name=Red Wooden Slab
tile.slab.planks.oak.painted.red.desc=A slab of wooden planks, stained red.
tile.slab.planks.oak.painted.green.name=Green Wooden Slab
tile.slab.planks.oak.painted.green.desc=A slab of wooden planks, stained green.
tile.slab.planks.oak.painted.brown.name=Brown Wooden Slab
tile.slab.planks.oak.painted.brown.desc=A slab of wooden planks, stained brown.
tile.slab.planks.oak.painted.blue.name=Blue Wooden Slab
tile.slab.planks.oak.painted.blue.desc=A slab of wooden planks, stained blue.
tile.slab.planks.oak.painted.purple.name=Purple Wooden Slab
tile.slab.planks.oak.painted.purple.desc=A slab of wooden planks, stained purple.
tile.slab.planks.oak.painted.cyan.name=Cyan Wooden Slab
tile.slab.planks.oak.painted.cyan.desc=A slab of wooden planks, stained cyan.
tile.slab.planks.oak.painted.silver.name=Light Gray Wooden Slab
tile.slab.planks.oak.painted.silver.desc=A slab of wooden planks, stained light gray.
tile.slab.planks.oak.painted.gray.name=Gray Wooden Slab
tile.slab.planks.oak.painted.gray.desc=A slab of wooden planks, stained gray.
tile.slab.planks.oak.painted.pink.name=Pink Wooden Slab
tile.slab.planks.oak.painted.pink.desc=A slab of wooden planks, stained pink.
tile.slab.planks.oak.painted.lime.name=Lime Wooden Slab
tile.slab.planks.oak.painted.lime.desc=A slab of wooden planks, stained lime.
tile.slab.planks.oak.painted.yellow.name=Yellow Wooden Slab
tile.slab.planks.oak.painted.yellow.desc=A slab of wooden planks, stained yellow.
tile.slab.planks.oak.painted.lightblue.name=Light Blue Wooden Slab
tile.slab.planks.oak.painted.lightblue.desc=A slab of wooden planks, stained light blue.
tile.slab.planks.oak.painted.magenta.name=Magenta Wooden Slab
tile.slab.planks.oak.painted.magenta.desc=A slab of wooden planks, stained magenta.
tile.slab.planks.oak.painted.orange.name=Orange Wooden Slab
tile.slab.planks.oak.painted.orange.desc=A slab of wooden planks, stained orange.
tile.slab.planks.oak.painted.white.name=White Wooden Slab
tile.slab.planks.oak.painted.white.desc=A slab of wooden planks, stained white.

tile.stairs.planks.oak.name=Wooden Stairs
tile.stairs.planks.oak.desc=Wooden block used for rapid vertical movement.
tile.stairs.cobble.stone.name=Cobblestone Stairs
tile.stairs.cobble.stone.desc=Cobblestone block used for rapid vertical movement.
tile.stairs.brick.stone.polished.name=Polished Stone Brick Stairs
tile.stairs.brick.stone.polished.desc=Polished stone brick block used for rapid vertical movement.
tile.stairs.brick.marble.name=Marble Brick Stairs
tile.stairs.brick.marble.desc=Marble brick block used for rapid vertical movement.
tile.stairs.cobble.basalt.name=Cobbled Basalt Stairs
tile.stairs.cobble.basalt.desc=Cobbled basalt block used for rapid vertical movement.
tile.stairs.cobble.limestone.name=Cobbled Limestone Stairs
tile.stairs.cobble.limestone.desc=Cobbled limestone block used for rapid vertical movement.
tile.stairs.cobble.granite.name=Cobbled Granite Stairs
tile.stairs.cobble.granite.desc=Cobbled granite block used for rapid vertical movement.
tile.stairs.brick.basalt.name=Basalt Brick Stairs
tile.stairs.brick.basalt.desc=Basalt brick block used for rapid vertical movement.
tile.stairs.brick.limestone.name=Limestone Brick Stairs
tile.stairs.brick.limestone.desc=Limestone brick block used for rapid vertical movement.
tile.stairs.brick.granite.name=Granite Brick Stairs
tile.stairs.brick.granite.desc=Granite brick block used for rapid vertical movement.
tile.stairs.brick.clay.name=Clay Brick Stairs
tile.stairs.brick.clay.desc=Clay brick block used for rapid vertical movement.
tile.stairs.brick.slate.name=Slate Brick Stairs
tile.stairs.brick.slate.desc=Slate brick block used for rapid vertical movement.
tile.stairs.brick.stone.name=Stone Brick Stairs
tile.stairs.brick.stone.desc=Stone brick block used for rapid vertical movement.

tile.stairs.planks.oak.painted.name=Mystery Wooden Stairs
tile.stairs.planks.oak.painted.desc=How did you get this?!
tile.stairs.planks.oak.painted.black.name=Black Wooden Stairs
tile.stairs.planks.oak.painted.black.desc=Wooden steps, stained black.
tile.stairs.planks.oak.painted.red.name=Red Wooden Stairs
tile.stairs.planks.oak.painted.red.desc=Wooden steps, stained red.
tile.stairs.planks.oak.painted.green.name=Green Wooden Stairs
tile.stairs.planks.oak.painted.green.desc=Wooden steps, stained green.
tile.stairs.planks.oak.painted.brown.name=Brown Wooden Stairs
tile.stairs.planks.oak.painted.brown.desc=Wooden steps, stained brown.
tile.stairs.planks.oak.painted.blue.name=Blue Wooden Stairs
tile.stairs.planks.oak.painted.blue.desc=Wooden steps, stained blue.
tile.stairs.planks.oak.painted.purple.name=Purple Wooden Stairs
tile.stairs.planks.oak.painted.purple.desc=Wooden steps, stained purple.
tile.stairs.planks.oak.painted.cyan.name=Cyan Wooden Stairs
tile.stairs.planks.oak.painted.cyan.desc=Wooden steps, stained cyan.
tile.stairs.planks.oak.painted.silver.name=Light Gray Wooden Stairs
tile.stairs.planks.oak.painted.silver.desc=Wooden steps, stained light gray.
tile.stairs.planks.oak.painted.gray.name=Gray Wooden Stairs
tile.stairs.planks.oak.painted.gray.desc=Wooden steps, stained gray.
tile.stairs.planks.oak.painted.pink.name=Pink Wooden Stairs
tile.stairs.planks.oak.painted.pink.desc=Wooden steps, stained pink.
tile.stairs.planks.oak.painted.lime.name=Lime Wooden Stairs
tile.stairs.planks.oak.painted.lime.desc=Wooden steps, stained lime.
tile.stairs.planks.oak.painted.yellow.name=Yellow Wooden Stairs
tile.stairs.planks.oak.painted.yellow.desc=Wooden steps, stained yellow.
tile.stairs.planks.oak.painted.lightblue.name=Light Blue Wooden Stairs
tile.stairs.planks.oak.painted.lightblue.desc=Wooden steps, stained light blue.
tile.stairs.planks.oak.painted.magenta.name=Magenta Wooden Stairs
tile.stairs.planks.oak.painted.magenta.desc=Wooden steps, stained magenta.
tile.stairs.planks.oak.painted.orange.name=Orange Wooden Stairs
tile.stairs.planks.oak.painted.orange.desc=Wooden steps, stained orange.
tile.stairs.planks.oak.painted.white.name=White Wooden Stairs
tile.stairs.planks.oak.painted.white.desc=Wooden steps, stained white.

tile.obsidian.name=Obsidian
tile.obsidian.desc=Rapidly cooled volcanic rock.

tile.glass.name=Glass
tile.glass.desc=Sand heated until it becomes translucent.
tile.glass.tinted.name=Tinted Glass
tile.glass.tinted.desc=Darkened glass that blocks light.

tile.grass.name=Grass
tile.grass.desc=Crisp, crunchy grass.
tile.grass.retro.name=Retro Grass
tile.grass.retro.desc=Crisp, crunchy grass. Smells old.
tile.grass.scorched.name=Scorched Grass
tile.grass.scorched.desc=Grass that has baked in the sun.

tile.path.dirt.name=Dirt Path
tile.path.dirt.desc=Dirt worn down by frequent travelling.

tile.dirt.name=Dirt
tile.dirt.desc=Crumbly brown dirt.
tile.dirt.scorched.name=Scorched Dirt
tile.dirt.scorched.desc=Dirt that has baked in the sun.
tile.dirt.scorched.rich.name=Rich Scorched Dirt
tile.dirt.scorched.rich.desc=Dirt that has baked in the sun, searing in minerals.

tile.mud.name=Mud
tile.mud.desc=Mud sodden to its core.
tile.mud.baked.name=Baked Mud
tile.mud.baked.desc=Mud that's been dried out and cracked.

tile.sponge.dry.name=Sponge
tile.sponge.dry.desc=A dry sponge, good for soaking up water.
tile.sponge.wet.name=Wet Sponge
tile.sponge.wet.desc=A sponge full of water.

tile.moss.stone.name=Mossy Stone
tile.moss.stone.desc=Moss covering a block of stone.
tile.moss.basalt.name=Mossy Basalt
tile.moss.basalt.desc=Moss covering a block of basalt.
tile.moss.limestone.name=Mossy Limestone
tile.moss.limestone.desc=Moss covering a block of limestone.
tile.moss.granite.name=Mossy Granite
tile.moss.granite.desc=Moss covering a block of granite.

tile.sand.name=Sand
tile.sand.desc=Gets everywhere.
tile.gravel.name=Gravel
tile.gravel.desc=A loose collection of pebbles.

tile.bedrock.name=Bedrock
tile.bedrock.desc=The toughest substance known to man.

tile.fluid.water.flowing.name=Flowing Water
tile.fluid.water.flowing.desc=Water that flows when placed.
tile.fluid.water.still.name=Still Water
tile.fluid.water.still.desc=Water that does not flow when placed.
tile.fluid.lava.flowing.name=Flowing Lava
tile.fluid.lava.flowing.desc=Lava that flows when placed.
tile.fluid.lava.still.name=Still Lava
tile.fluid.lava.still.desc=Lava that does not flow when placed.

tile.log.oak.name=Oak Log
tile.log.oak.desc=A log from an oak tree.
tile.log.pine.name=Pine Log
tile.log.pine.desc=A log from a pine tree.
tile.log.birch.name=Birch Log
tile.log.birch.desc=A log from a birch tree.
tile.log.cherry.name=Cherry Log
tile.log.cherry.desc=A log from a cherry tree.
tile.log.eucalyptus.name=Eucalyptus Log
tile.log.eucalyptus.desc=A log from a eucalyptus tree.
tile.log.oak.mossy.name=Mossy Oak Log
tile.log.oak.mossy.desc=A log from a mossy oak tree.

tile.leaves.oak.name=Oak Leaves
tile.leaves.oak.desc=Leaves from an oak tree.
tile.leaves.pine.name=Pine Leaves
tile.leaves.pine.desc=Leaves from a pine tree.
tile.leaves.birch.name=Birch Leaves
tile.leaves.birch.desc=Leaves from a birch tree.
tile.leaves.cherry.name=Cherry Leaves
tile.leaves.cherry.desc=Leaves from a cherry tree.
tile.leaves.eucalyptus.name=Eucalyptus Leaves
tile.leaves.eucalyptus.desc=Leaves from a eucalyptus tree.
tile.leaves.oak.retro.name=Retro Leaves
tile.leaves.oak.retro.desc=Leaves from long ago.
tile.leaves.shrub.name=Shrub Leaves
tile.leaves.shrub.desc=Leaves from a shrub.
tile.leaves.cherry.flowering.name=Flowering Cherry Leaves
tile.leaves.cherry.flowering.desc=Leaves from a cherry tree that are budding with fruit.
tile.leaves.cacao.name=Cacao Leaves
tile.leaves.cacao.desc=Leaves from a cacao tree.
tile.leaves.caatinga.name=Caatinga Leaves
tile.leaves.caatinga.desc=Leaves from a caatinga tree.

tile.sapling.oak.name=Oak Sapling
tile.sapling.oak.desc=Plant to grow an oak tree.
tile.sapling.pine.name=Pine Sapling
tile.sapling.pine.desc=Plant to grow a pine tree.
tile.sapling.birch.name=Birch Sapling
tile.sapling.birch.desc=Plant to grow a birch tree.
tile.sapling.cherry.name=Cherry Sapling
tile.sapling.cherry.desc=Plant to grow a cherry tree.
tile.sapling.eucalyptus.name=Eucalyptus Sapling
tile.sapling.eucalyptus.desc=Plant to grow a eucalyptus tree.
tile.sapling.oak.retro.name=Retro Oak Sapling
tile.sapling.oak.retro.desc=Plant to grow a tree from long ago.
tile.sapling.shrub.name=Shrub Sapling
tile.sapling.shrub.desc=Plant to grow a shrub.
tile.sapling.cacao.name=Cacao Sapling
tile.sapling.cacao.desc=Plant to grow a cacao tree.

tile.tallgrass.name=Tall Grass
tile.tallgrass.desc=Lush, growing grass.
tile.tallgrass.fern.name=Fern
tile.tallgrass.fern.desc=A fern plant.
tile.deadbush.name=Dead Bush
tile.deadbush.desc=A dried and withered plant.
tile.spinifex.name=Spinifex
tile.spinifex.desc=A spindly, thin grass from dry regions.
tile.algae.name=Algae
tile.algae.desc=Gooey vegetation that floats on the water's surface.

tile.flower.yellow.name=Dandelion
tile.flower.yellow.desc=A beautiful yellow flower.
tile.flower.red.name=Rose
tile.flower.red.desc=A beautiful red flower.
tile.flower.purple.name=Heather
tile.flower.purple.desc=Sprigs of purple petals. Brings good luck.
tile.flower.lightblue.name=Bluebell
tile.flower.lightblue.desc=A sad-looking blue flower.
tile.flower.pink.name=Orchids
tile.flower.pink.desc=A bouquet of beautiful pink flowers.

tile.mushroom.red.name=Red Mushroom
tile.mushroom.red.desc=A tasty red mushroom. Good for stew.
tile.mushroom.brown.name=Brown Mushroom
tile.mushroom.brown.desc=A tasty brown mushroom. Good for stew.

tile.ore.coal.stone.name=Stone Coal Ore
tile.ore.coal.stone.desc=A chunk of coal embedded in stone.
tile.ore.coal.basalt.name=Basalt Coal Ore
tile.ore.coal.basalt.desc=A chunk of coal embedded in basalt.
tile.ore.coal.limestone.name=Limestone Coal Ore
tile.ore.coal.limestone.desc=A chunk of coal embedded in limestone.
tile.ore.coal.granite.name=Granite Coal Ore
tile.ore.coal.granite.desc=A chunk of coal embedded in granite.

tile.ore.iron.stone.name=Stone Iron Ore
tile.ore.iron.stone.desc=Iron nuggets embedded in stone.
tile.ore.iron.basalt.name=Basalt Iron Ore
tile.ore.iron.basalt.desc=Iron nuggets embedded in basalt.
tile.ore.iron.limestone.name=Limestone Iron Ore
tile.ore.iron.limestone.desc=Iron nuggets embedded in limestone.
tile.ore.iron.granite.name=Granite Iron Ore
tile.ore.iron.granite.desc=Iron nuggets embedded in granite.

tile.ore.gold.stone.name=Stone Gold Ore
tile.ore.gold.stone.desc=Gold nuggets embedded in stone.
tile.ore.gold.basalt.name=Basalt Gold Ore
tile.ore.gold.basalt.desc=Gold nuggets embedded in basalt.
tile.ore.gold.limestone.name=Limestone Gold Ore
tile.ore.gold.limestone.desc=Gold nuggets embedded in limestone.
tile.ore.gold.granite.name=Granite Gold Ore
tile.ore.gold.granite.desc=Gold nuggets embedded in granite.

tile.ore.lapis.stone.name=Stone Lapis Lazuli Ore
tile.ore.lapis.stone.desc=Chunks of lapis lazuli embedded in stone.
tile.ore.lapis.basalt.name=Basalt Lapis Lazuli Ore
tile.ore.lapis.basalt.desc=Chunks of lapis lazuli embedded in basalt.
tile.ore.lapis.limestone.name=Limestone Lapis Lazuli Ore
tile.ore.lapis.limestone.desc=Chunks of lapis lazuli embedded in limestone.
tile.ore.lapis.granite.name=Granite Lapis Lazuli Ore
tile.ore.lapis.granite.desc=Chunks of lapis lazuli embedded in granite.

tile.ore.redstone.stone.name=Stone Redstone Ore
tile.ore.redstone.stone.desc=Red dust embedded in stone.
tile.ore.redstone.basalt.name=Basalt Redstone Ore
tile.ore.redstone.basalt.desc=Red dust embedded in basalt.
tile.ore.redstone.limestone.name=Limestone Redstone Ore
tile.ore.redstone.limestone.desc=Red dust embedded in limestone.
tile.ore.redstone.granite.name=Granite Redstone Ore
tile.ore.redstone.granite.desc=Red dust embedded in granite.
tile.ore.redstone.glowing.stone.name=Glowing Stone Redstone Ore
tile.ore.redstone.glowing.stone.desc=Red dust embedded in stone. Emits a faint light.
tile.ore.redstone.glowing.basalt.name=Glowing Basalt Redstone Ore
tile.ore.redstone.glowing.basalt.desc=Red dust embedded in basalt. Emits a faint light.
tile.ore.redstone.glowing.limestone.name=Glowing Limestone Redstone Ore
tile.ore.redstone.glowing.limestone.desc=Red dust embedded in limestone. Emits a faint light.
tile.ore.redstone.glowing.granite.name=Glowing Granite Redstone Ore
tile.ore.redstone.glowing.granite.desc=Red dust embedded in granite. Emits a faint light.

tile.ore.diamond.stone.name=Stone Diamond Ore
tile.ore.diamond.stone.desc=A chunk of diamond embedded in stone.
tile.ore.diamond.basalt.name=Basalt Diamond Ore
tile.ore.diamond.basalt.desc=A chunk of diamond embedded in basalt.
tile.ore.diamond.limestone.name=Limestone Diamond Ore
tile.ore.diamond.limestone.desc=A chunk of diamond embedded in limestone.
tile.ore.diamond.granite.name=Granite Diamond Ore
tile.ore.diamond.granite.desc=A chunk of diamond embedded in granite.

tile.ore.nethercoal.netherrack.name=Nether Coal Ore
tile.ore.nethercoal.netherrack.desc=A lump of Nether Coal embedded in netherrack.

tile.block.coal.name=Block of Coal
tile.block.coal.desc=A solid block of coal.
tile.block.iron.name=Block of Iron
tile.block.iron.desc=A solid block of iron. Heavy!
tile.block.gold.name=Block of Gold
tile.block.gold.desc=A solid block of gold, for flaunting your bling.
tile.block.lapis.name=Block of Lapis Lazuli
tile.block.lapis.desc=A solid block of lapis lazuli.
tile.block.redstone.name=Block of Redstone
tile.block.redstone.desc=A solid block of redstone.
tile.block.diamond.name=Block of Diamond
tile.block.diamond.desc=A solid block of diamond. Well done you.
tile.block.nethercoal.name=Block of Nether Coal
tile.block.nethercoal.desc=A solid block of Nether Coal.
tile.block.steel.name=Block of Steel
tile.block.steel.desc=A solid block of steel.
tile.block.quartz.name=Block of Quartz
tile.block.quartz.desc=A solid block of quartz.
tile.block.olivine.name=Block of Olivine
tile.block.olivine.desc=A solid block of olivine.
tile.block.charcoal.name=Block of Charcoal
tile.block.charcoal.desc=A solid block of charcoal.

tile.wire.redstone.name=Redstone Wire
tile.wire.redstone.desc=A strand of redstone dust laid on the ground.

tile.torch.redstone.idle.name=Redstone Torch
tile.torch.redstone.idle.desc=Emits a constant redstone signal.
tile.torch.redstone.active.name=Redstone Torch
tile.torch.redstone.active.desc=Emits a constant redstone signal.

tile.button.stone.name=Stone Button
tile.button.stone.desc=Emits a brief redstone signal when pressed.

tile.lever.cobble.stone.name=Cobblestone Lever
tile.lever.cobble.stone.desc=Allows turning a redstone signal on or off.

tile.pressureplate.stone.name=Stone Pressure Plate
tile.pressureplate.stone.desc=Emits a redstone signal when living creatures step on it.
tile.pressureplate.planks.oak.name=Wooden Pressure Plate
tile.pressureplate.planks.oak.desc=Emits a redstone signal when anything steps on it.
tile.pressureplate.cobble.stone.name=Cobblestone Pressure Plate
tile.pressureplate.cobble.stone.desc=Emits a redstone signal when players step on it.

tile.motionsensor.idle.name=Motion Sensor
tile.motionsensor.idle.desc=Emits a redstone signal when something moves past it.
tile.motionsensor.active.name=Active Motion Sensor
tile.motionsensor.active.desc=Emits a redstone signal when something moves past it.

tile.repeater.idle.name=Redstone Repeater
tile.repeater.idle.desc=Repeats redstone signals over a distance.
tile.repeater.active.name=Redstone Repeater
tile.repeater.active.desc=Repeats redstone signals over a distance.

tile.piston.base.name=Piston
tile.piston.base.desc=Pushes blocks but does not pull them.
tile.piston.base.sticky.name=Sticky Piston
tile.piston.base.sticky.desc=Pushes and pulls blocks.
tile.piston.head.name=Piston Head
tile.piston.head.desc=The pushy part of the piston.
tile.piston.moving.name=Piston Mover
tile.piston.moving.desc=The invisible moving part of the piston.

tile.noteblock.name=Note Block
tile.noteblock.desc=Plays a musical note when powered.

tile.rail.name=Rail
tile.rail.desc=For rapid horizontal movement via minecart.
tile.rail.powered.name=Powered Rail
tile.rail.powered.desc=Makes minecarts go faster when powered.
tile.rail.detector.name=Detector Rail
tile.rail.detector.desc=Emits a redstone signal when a minecart crosses it.

tile.spikes.name=Spike Trap
tile.spikes.desc=Deactivates when powered. Technically a war crime.

tile.dispenser.cobble.stone.name=Dispenser
tile.dispenser.cobble.stone.desc=Fires items out of the hole in the front.

tile.trapdoor.planks.oak.name=Oak Trapdoor
tile.trapdoor.planks.oak.desc=Like a door, but flat.
tile.trapdoor.iron.name=Iron Trapdoor
tile.trapdoor.iron.desc=Like a door, but flat and made of iron.
tile.trapdoor.glass.name=Glass Trapdoor
tile.trapdoor.glass.desc=Useless at its job.

tile.tnt.name=TNT
tile.tnt.desc=Goes off with a bang.

tile.door.planks.oak.bottom.name=Bottom Wooden Door
tile.door.planks.oak.bottom.desc=/give Honeydew 64 46
tile.door.planks.oak.top.name=Top Wooden Door
tile.door.planks.oak.top.desc=Oh, wait, that's not TNT, that's half a door.
tile.door.iron.bottom.name=Bottom Iron Door
tile.door.iron.bottom.desc=Not much good on its own.
tile.door.iron.top.name=Top Iron Door
tile.door.iron.top.desc=Could use a friend.

tile.mesh.name=Mesh Block
tile.mesh.desc=Allows items to pass through but nothing else.
tile.mesh.gold.name=Gold Mesh Block
tile.mesh.gold.desc=Allows a specified item to pass through but nothing else.

tile.bed.name=Bed
tile.bed.desc=Bed!
tile.seat.name=Seat
tile.seat.desc=Sit down and relax.

tile.cobweb.name=Cobweb
tile.cobweb.desc=Sticky silky strands woven by spiders.

tile.fire.name=Fire
tile.fire.desc=Ouch, fire hot!
tile.brazier.inactive.name=Brazier
tile.brazier.inactive.desc=A safe place to keep a fire.
tile.brazier.active.name=Lit Brazier
tile.brazier.active.desc=A safe place to keep a fire.

tile.mobspawner.name=Mob Spawner
tile.mobspawner.desc=A cage filled with horror.
tile.mobspawner.deactivated.name=Deactivated Mob Spawner
tile.mobspawner.deactivated.desc=A cage no longer filled with horror.

tile.workbench.name=Workbench
tile.workbench.desc=For bigger projects.

tile.furnace.stone.idle.name=Furnace
tile.furnace.stone.idle.desc=For melting, heating, and cooking blocks and items.
tile.furnace.stone.active.name=Lit Furnace
tile.furnace.stone.active.desc=For melting, heating, and cooking blocks and items.
tile.furnace.blast.idle.name=Blast Furnace
tile.furnace.blast.idle.desc=Burns hotter than a normal furnace.
tile.furnace.blast.active.name=Lit Blast Furnace
tile.furnace.blast.active.desc=Burns hotter than a normal furnace.

tile.trommel.idle.name=Trommel
tile.trommel.idle.desc=A machine that separates dirt from other useful items.
tile.trommel.active.name=Lit Trommel
tile.trommel.active.desc=A machine that separates dirt from other useful items.

tile.chest.planks.oak.name=Wooden Chest
tile.chest.planks.oak.desc=A place to store your items.
tile.chest.planks.oak.painted.name=Mystery Wooden Chest
tile.chest.planks.oak.painted.desc=How did you get this?!
tile.chest.planks.oak.painted.black.name=Black Wooden Chest
tile.chest.planks.oak.painted.black.desc=A place to store your items.
tile.chest.planks.oak.painted.red.name=Red Wooden Chest
tile.chest.planks.oak.painted.red.desc=A place to store your items.
tile.chest.planks.oak.painted.green.name=Green Wooden Chest
tile.chest.planks.oak.painted.green.desc=A place to store your items.
tile.chest.planks.oak.painted.brown.name=Brown Wooden Chest
tile.chest.planks.oak.painted.brown.desc=A place to store your items.
tile.chest.planks.oak.painted.blue.name=Blue Wooden Chest
tile.chest.planks.oak.painted.blue.desc=A place to store your items.
tile.chest.planks.oak.painted.purple.name=Purple Wooden Chest
tile.chest.planks.oak.painted.purple.desc=A place to store your items.
tile.chest.planks.oak.painted.cyan.name=Cyan Wooden Chest
tile.chest.planks.oak.painted.cyan.desc=A place to store your items.
tile.chest.planks.oak.painted.silver.name=Light Gray Wooden Chest
tile.chest.planks.oak.painted.silver.desc=A place to store your items.
tile.chest.planks.oak.painted.gray.name=Gray Wooden Chest
tile.chest.planks.oak.painted.gray.desc=A place to store your items.
tile.chest.planks.oak.painted.pink.name=Pink Wooden Chest
tile.chest.planks.oak.painted.pink.desc=A place to store your items.
tile.chest.planks.oak.painted.lime.name=Lime Wooden Chest
tile.chest.planks.oak.painted.lime.desc=A place to store your items.
tile.chest.planks.oak.painted.yellow.name=Yellow Wooden Chest
tile.chest.planks.oak.painted.yellow.desc=A place to store your items.
tile.chest.planks.oak.painted.lightblue.name=Light Blue Wooden Chest
tile.chest.planks.oak.painted.lightblue.desc=A place to store your items.
tile.chest.planks.oak.painted.magenta.name=Magenta Wooden Chest
tile.chest.planks.oak.painted.magenta.desc=A place to store your items.
tile.chest.planks.oak.painted.orange.name=Orange Wooden Chest
tile.chest.planks.oak.painted.orange.desc=A place to store your items.
tile.chest.planks.oak.painted.white.name=White Wooden Chest
tile.chest.planks.oak.painted.white.desc=A place to store your items.
tile.chest.legacy.name=Legacy Chest

tile.crops.wheat.name=Wheat Crops
tile.crops.wheat.desc=Wheat, plucked from the ground.
tile.crops.pumpkin.name=Pumpkin Crops
tile.crops.pumpkin.desc=A ripening pumpkin, plucked from the ground.

tile.farmland.dirt.name=Farmland
tile.farmland.dirt.desc=Tilled soil for growing crops.

tile.sign.post.planks.oak.name=Oak Signpost
tile.sign.post.planks.oak.desc=A free-standing oak sign.
tile.sign.wall.planks.oak.name=Oak Wall Sign
tile.sign.wall.planks.oak.desc=An oak sign placed on a wall.

tile.layer.snow.name=Snow Layer
tile.layer.snow.desc=A flat layer of snow.
tile.layer.leaves.oak.name=Leaf Pile
tile.layer.leaves.oak.desc=A pile of leaves.
tile.layer.slate.name=Slate Layer
tile.layer.slate.desc=A flat sheet of slate.

tile.ice.name=Ice
tile.ice.desc=Slippery frozen water.
tile.ice.perma.name=Perma-Ice
tile.ice.perma.desc=Ice imbued with the essence of stone.

tile.block.snow.name=Block of Snow
tile.block.snow.desc=Lots of snow compacted into a block.

tile.cactus.name=Cactus
tile.cactus.desc=A spiky plant that grows in the desert.

tile.block.clay.name=Block of Clay
tile.block.clay.desc=A block of compacted clay.

tile.sugarcane.name=Sugarcane
tile.sugarcane.desc=Not as sweet as you.

tile.block.sugarcane.name=Block of Sugarcane
tile.block.sugarcane.desc=One very big sugar cube.
tile.block.sugarcane.baked.name=Baked Block of Sugarcane
tile.block.sugarcane.baked.desc=Smells absolutely delicious.

tile.jukebox.name=Jukebox
tile.jukebox.desc=Plays your favourite tunes, assuming you have the right record.

tile.pumpkin.name=Pumpkin
tile.pumpkin.desc=An orange squash that grows in the wild.
tile.pumpkin.carved.idle.name=Carved Pumpkin
tile.pumpkin.carved.idle.desc=An orange squash with a spooky face.
tile.pumpkin.carved.active.name=Jack 'o' Lantern
tile.pumpkin.carved.active.desc=An orange squash with a spooky face, lit by a torch.

tile.netherrack.name=Netherrack
tile.netherrack.desc=Dark red rock that burns forever.
tile.netherrack.igneous.name=Igneous Netherrack
tile.netherrack.igneous.desc=Extreme heat has made this rock glow from inside.

tile.soulsand.name=Soul Sand
tile.soulsand.desc=Squishy brown sand that's tough to walk through.

tile.glowstone.name=Block of Glowstone
tile.glowstone.desc=Constantly emits a strong yellowish light.

tile.portal.nether.name=Nether Portal
tile.portal.nether.desc=A portal to the Nether.
tile.portal.paradise.name=Paradise Portal
tile.portal.paradise.desc=A portal to Paradise.

tile.cake.name=Cake
tile.cake.desc=I just can't cake it any more.

tile.lamp.idle.name=Lamp
tile.lamp.idle.desc=How did you get this?!
tile.lamp.idle.black.name=Black Lamp
tile.lamp.idle.black.desc=A redstone lamp that can emit light. Tinted black.
tile.lamp.idle.red.name=Red Lamp
tile.lamp.idle.red.desc=A redstone lamp that can emit light. Tinted red.
tile.lamp.idle.green.name=Green Lamp
tile.lamp.idle.green.desc=A redstone lamp that can emit light. Tinted green.
tile.lamp.idle.brown.name=Brown Lamp
tile.lamp.idle.brown.desc=A redstone lamp that can emit light. Tinted brown.
tile.lamp.idle.blue.name=Blue Lamp
tile.lamp.idle.blue.desc=A redstone lamp that can emit light. Tinted blue.
tile.lamp.idle.purple.name=Purple Lamp
tile.lamp.idle.purple.desc=A redstone lamp that can emit light. Tinted purple.
tile.lamp.idle.cyan.name=Cyan Lamp
tile.lamp.idle.cyan.desc=A redstone lamp that can emit light. Tinted cyan.
tile.lamp.idle.silver.name=Light Gray Lamp
tile.lamp.idle.silver.desc=A redstone lamp that can emit light. Tinted light gray.
tile.lamp.idle.gray.name=Gray Lamp
tile.lamp.idle.gray.desc=A redstone lamp that can emit light. Tinted gray.
tile.lamp.idle.pink.name=Pink Lamp
tile.lamp.idle.pink.desc=A redstone lamp that can emit light. Tinted pink.
tile.lamp.idle.lime.name=Lime Lamp
tile.lamp.idle.lime.desc=A redstone lamp that can emit light. Tinted lime.
tile.lamp.idle.yellow.name=Yellow Lamp
tile.lamp.idle.yellow.desc=A redstone lamp that can emit light. Tinted yellow.
tile.lamp.idle.lightblue.name=Light Blue Lamp
tile.lamp.idle.lightblue.desc=A redstone lamp that can emit light. Tinted light blue.
tile.lamp.idle.magenta.name=Magenta Lamp
tile.lamp.idle.magenta.desc=A redstone lamp that can emit light. Tinted magenta.
tile.lamp.idle.orange.name=Orange Lamp
tile.lamp.idle.orange.desc=A redstone lamp that can emit light. Tinted orange.
tile.lamp.idle.white.name=White Lamp
tile.lamp.idle.white.desc=A redstone lamp that can emit light.

tile.lamp.active.name=Lit Lamp
tile.lamp.active.desc=How did you get this?!
tile.lamp.active.black.name=Lit Black Lamp
tile.lamp.active.black.desc=A redstone lamp that emits light. Tinted black.
tile.lamp.active.red.name=Lit Red Lamp
tile.lamp.active.red.desc=A redstone lamp that emits light. Tinted red.
tile.lamp.active.green.name=Lit Green Lamp
tile.lamp.active.green.desc=A redstone lamp that emits light. Tinted green.
tile.lamp.active.brown.name=Lit Brown Lamp
tile.lamp.active.brown.desc=A redstone lamp that emits light. Tinted brown.
tile.lamp.active.blue.name=Lit Blue Lamp
tile.lamp.active.blue.desc=A redstone lamp that emits light. Tinted blue.
tile.lamp.active.purple.name=Lit Purple Lamp
tile.lamp.active.purple.desc=A redstone lamp that emits light. Tinted purple.
tile.lamp.active.cyan.name=Lit Cyan Lamp
tile.lamp.active.cyan.desc=A redstone lamp that emits light. Tinted cyan.
tile.lamp.active.silver.name=Lit Light Gray Lamp
tile.lamp.active.silver.desc=A redstone lamp that emits light. Tinted light gray.
tile.lamp.active.gray.name=Lit Gray Lamp
tile.lamp.active.gray.desc=A redstone lamp that emits light. Tinted gray.
tile.lamp.active.pink.name=Lit Pink Lamp
tile.lamp.active.pink.desc=A redstone lamp that emits light. Tinted pink.
tile.lamp.active.lime.name=Lit Lime Lamp
tile.lamp.active.lime.desc=A redstone lamp that emits light. Tinted lime.
tile.lamp.active.yellow.name=Yellow Lamp
tile.lamp.active.yellow.desc=A redstone lamp that emits light. Tinted yellow.
tile.lamp.active.lightblue.name=Light Blue Lamp
tile.lamp.active.lightblue.desc=A redstone lamp that emits light. Tinted light blue.
tile.lamp.active.magenta.name=Magenta Lamp
tile.lamp.active.magenta.desc=A redstone lamp that emits light. Tinted magenta.
tile.lamp.active.orange.name=Orange Lamp
tile.lamp.active.orange.desc=A redstone lamp that emits light. Tinted orange.
tile.lamp.active.white.name=White Lamp
tile.lamp.active.white.desc=A redstone lamp that emits light.

tile.stone.polished.name=Polished Stone
tile.stone.polished.desc=A polished block of stone.
tile.granite.polished.name=Polished Granite
tile.granite.polished.desc=A polished block of granite.
tile.limestone.polished.name=Polished Limestone
tile.limestone.polished.desc=A polished block of limestone.
tile.basalt.polished.name=Polished Basalt
tile.basalt.polished.desc=A polished block of basalt.
tile.slate.polished.name=Polished Slate
tile.slate.polished.desc=A polished block of slate.

tile.candle.wax.soul.name=Soul Wax Candle
tile.candle.wax.soul.desc=A waxy brown candle that glows with an unnatural light.

tile.basket.name=Basket
tile.basket.desc=A wicker container for holding items.

tile.overlay.pebbles.name=Pebbles
tile.overlay.pebbles.desc=A cluster of pebbles.

tile.fence.chainlink.name=Chainlink Fence
tile.fence.chainlink.desc=A fence made of interconnected chain links. Can be climbed!
tile.fence.paper_wall.name=Paper Wall Fence
tile.fence.paper_wall.desc=A fence made of delicate paper. Be careful!

tile.lantern.firefly.green.name=Green Firefly Lantern
tile.lantern.firefly.green.desc=A glass jar containing a swarm of green fireflies.
tile.lantern.firefly.orange.name=Orange Firefly Lantern
tile.lantern.firefly.orange.desc=A glass jar containing a swarm of orange fireflies.
tile.lantern.firefly.blue.name=Blue Firefly Lantern
tile.lantern.firefly.blue.desc=A glass jar containing a swarm of blue fireflies.
tile.lantern.firefly.red.name=Red Firefly Lantern
tile.lantern.firefly.red.desc=A glass jar containing a swarm of red fireflies.

tile.flag.name=Flag
tile.flag.desc=A flag to mark your territory.

tile.paper_wall.name=Paper Wall
tile.paper_wall.desc=A wall made of delicate paper. Be careful!

tile.trapdoor.planks.oak.painted.name=Painted Trapdoor
tile.trapdoor.planks.oak.painted.desc=How did you get this?!
tile.trapdoor.planks.oak.painted.black.name=Black Oak Trapdoor
tile.trapdoor.planks.oak.painted.black.desc=Like a door, but flat and painted black.
tile.trapdoor.planks.oak.painted.red.name=Red Oak Trapdoor
tile.trapdoor.planks.oak.painted.red.desc=Like a door, but flat and painted red.
tile.trapdoor.planks.oak.painted.green.name=Green Oak Trapdoor
tile.trapdoor.planks.oak.painted.green.desc=Like a door, but flat and painted green.
tile.trapdoor.planks.oak.painted.brown.name=Brown Oak Trapdoor
tile.trapdoor.planks.oak.painted.brown.desc=Like a door, but flat and painted brown.
tile.trapdoor.planks.oak.painted.blue.name=Blue Oak Trapdoor
tile.trapdoor.planks.oak.painted.blue.desc=Like a door, but flat and painted blue.
tile.trapdoor.planks.oak.painted.purple.name=Purple Oak Trapdoor
tile.trapdoor.planks.oak.painted.purple.desc=Like a door, but flat and painted purple.
tile.trapdoor.planks.oak.painted.cyan.name=Cyan Oak Trapdoor
tile.trapdoor.planks.oak.painted.cyan.desc=Like a door, but flat and painted cyan.
tile.trapdoor.planks.oak.painted.silver.name=Light Gray Oak Trapdoor
tile.trapdoor.planks.oak.painted.silver.desc=Like a door, but flat and painted light gray.
tile.trapdoor.planks.oak.painted.gray.name=Gray Oak Trapdoor
tile.trapdoor.planks.oak.painted.gray.desc=Like a door, but flat and painted gray.
tile.trapdoor.planks.oak.painted.pink.name=Pink Oak Trapdoor
tile.trapdoor.planks.oak.painted.pink.desc=Like a door, but flat and painted pink.
tile.trapdoor.planks.oak.painted.lime.name=Lime Oak Trapdoor
tile.trapdoor.planks.oak.painted.lime.desc=Like a door, but flat and painted lime.
tile.trapdoor.planks.oak.painted.yellow.name=Yellow Oak Trapdoor
tile.trapdoor.planks.oak.painted.yellow.desc=Like a door, but flat and painted yellow.
tile.trapdoor.planks.oak.painted.lightblue.name=Light Blue Oak Trapdoor
tile.trapdoor.planks.oak.painted.lightblue.desc=Like a door, but flat and painted light blue.
tile.trapdoor.planks.oak.painted.magenta.name=Magenta Oak Trapdoor
tile.trapdoor.planks.oak.painted.magenta.desc=Like a door, but flat and painted magenta.
tile.trapdoor.planks.oak.painted.orange.name=Orange Oak Trapdoor
tile.trapdoor.planks.oak.painted.orange.desc=Like a door, but flat and painted orange.
tile.trapdoor.planks.oak.painted.white.name=White Oak Trapdoor
tile.trapdoor.planks.oak.painted.white.desc=Like a door, but flat and painted white.

tile.door.planks.oak.painted.bottom.name=Bottom Painted Wooden Door
tile.door.planks.oak.painted.bottom.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.black.name=Black Bottom Wooden Door
tile.door.planks.oak.painted.bottom.black.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.red.name=Red Bottom Wooden Door
tile.door.planks.oak.painted.bottom.red.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.green.name=Green Bottom Wooden Door
tile.door.planks.oak.painted.bottom.green.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.brown.name=Brown Bottom Wooden Door
tile.door.planks.oak.painted.bottom.brown.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.blue.name=Blue Bottom Wooden Door
tile.door.planks.oak.painted.bottom.blue.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.purple.name=Purple Bottom Wooden Door
tile.door.planks.oak.painted.bottom.purple.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.cyan.name=Cyan Bottom Wooden Door
tile.door.planks.oak.painted.bottom.cyan.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.silver.name=Light Gray Bottom Wooden Door
tile.door.planks.oak.painted.bottom.silver.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.gray.name=Gray Bottom Wooden Door
tile.door.planks.oak.painted.bottom.gray.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.pink.name=Pink Bottom Wooden Door
tile.door.planks.oak.painted.bottom.pink.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.lime.name=Lime Bottom Wooden Door
tile.door.planks.oak.painted.bottom.lime.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.yellow.name=Yellow Bottom Wooden Door
tile.door.planks.oak.painted.bottom.yellow.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.lightblue.name=Light Blue Bottom Wooden Door
tile.door.planks.oak.painted.bottom.lightblue.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.magenta.name=Magenta Bottom Wooden Door
tile.door.planks.oak.painted.bottom.magenta.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.orange.name=Orange Bottom Wooden Door
tile.door.planks.oak.painted.bottom.orange.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.white.name=White Bottom Wooden Door
tile.door.planks.oak.painted.bottom.white.desc=How did you get this?!

tile.door.planks.oak.painted.top.name=Top Painted Wooden Door
tile.door.planks.oak.painted.top.desc=How did you get this?!
tile.door.planks.oak.painted.top.black.name=Black Top Wooden Door
tile.door.planks.oak.painted.top.black.desc=How did you get this?!
tile.door.planks.oak.painted.top.red.name=Red Top Wooden Door
tile.door.planks.oak.painted.top.red.desc=How did you get this?!
tile.door.planks.oak.painted.top.green.name=Green Top Wooden Door
tile.door.planks.oak.painted.top.green.desc=How did you get this?!
tile.door.planks.oak.painted.top.brown.name=Brown Top Wooden Door
tile.door.planks.oak.painted.top.brown.desc=How did you get this?!
tile.door.planks.oak.painted.top.blue.name=Blue Top Wooden Door
tile.door.planks.oak.painted.top.blue.desc=How did you get this?!
tile.door.planks.oak.painted.top.purple.name=Purple Top Wooden Door
tile.door.planks.oak.painted.top.purple.desc=How did you get this?!
tile.door.planks.oak.painted.top.cyan.name=Cyan Top Wooden Door
tile.door.planks.oak.painted.top.cyan.desc=How did you get this?!
tile.door.planks.oak.painted.top.silver.name=Light Gray Top Wooden Door
tile.door.planks.oak.painted.top.silver.desc=How did you get this?!
tile.door.planks.oak.painted.top.gray.name=Gray Top Wooden Door
tile.door.planks.oak.painted.top.gray.desc=How did you get this?!
tile.door.planks.oak.painted.top.pink.name=Pink Top Wooden Door
tile.door.planks.oak.painted.top.pink.desc=How did you get this?!
tile.door.planks.oak.painted.top.lime.name=Lime Top Wooden Door
tile.door.planks.oak.painted.top.lime.desc=How did you get this?!
tile.door.planks.oak.painted.top.yellow.name=Yellow Top Wooden Door
tile.door.planks.oak.painted.top.yellow.desc=How did you get this?!
tile.door.planks.oak.painted.top.lightblue.name=Light Blue Top Wooden Door
tile.door.planks.oak.painted.top.lightblue.desc=How did you get this?!
tile.door.planks.oak.painted.top.magenta.name=Magenta Top Wooden Door
tile.door.planks.oak.painted.top.magenta.desc=How did you get this?!
tile.door.planks.oak.painted.top.orange.name=Orange Top Wooden Door
tile.door.planks.oak.painted.top.orange.desc=How did you get this?!
tile.door.planks.oak.painted.top.white.name=White Top Wooden Door
tile.door.planks.oak.painted.top.white.desc=How did you get this?!

tile.door.glass.top.name=Glass Top Door
tile.door.glass.top.desc=You shouldn't be seeing this.
tile.door.glass.bottom.name=Glass Bottom Door
tile.door.glass.bottom.desc=And that's not just because it's glass.

tile.rope.name=Rope
tile.rope.desc=Rope, rope, rope your boat.
\ No newline at end of file
+tile.stone.name=Stone
tile.stone.desc=A block of solid stone.
tile.basalt.name=Basalt
tile.basalt.desc=A block of solid basalt.
tile.limestone.name=Limestone
tile.limestone.desc=A block of solid limestone.
tile.granite.name=Granite
tile.granite.desc=A block of solid granite.
tile.marble.name=Marble
tile.marble.desc=A block of solid marble.
tile.slate.name=Slate
tile.slate.desc=A block of solid slate.
tile.permafrost.name=Permafrost
tile.permafrost.desc=A block of frozen stone.

tile.cobble.stone.name=Cobblestone
tile.cobble.stone.desc=Stone, smashed apart and reconstituted.
tile.cobble.stone.mossy.name=Mossy Cobblestone
tile.cobble.stone.mossy.desc=Cobblestone with added greenery.
tile.cobble.basalt.name=Cobbled Basalt
tile.cobble.basalt.desc=Basalt, smashed apart and reconstituted.
tile.cobble.limestone.name=Cobbled Limestone
tile.cobble.limestone.desc=Limestone, smashed apart and reconstituted.
tile.cobble.granite.name=Cobbled Granite
tile.cobble.granite.desc=Granite, smashed apart and reconstituted.
tile.cobble.permafrost.name=Cobbled Permafrost
tile.cobble.permafrost.desc=Permafrost, smashed apart and reconstituted.

tile.pillar.marble.name=Marble Pillar
tile.pillar.marble.desc=A block of marble engraved into a pillar.
tile.capstone.marble.name=Marble Capstone
tile.capstone.marble.desc=A pillar capstone made of solid marble.

tile.sandstone.name=Sandstone
tile.sandstone.desc=Compacted sand.

tile.stone.carved.name=Carved Stone
tile.stone.carved.desc=Polished Stone with lines hewn through the middle.
tile.granite.carved.name=Carved Granite
tile.granite.carved.desc=Polished Granite with lines hewn through the middle.
tile.limestone.carved.name=Carved Limestone
tile.limestone.carved.desc=Polished Limestone with lines hewn through the middle.
tile.basalt.carved.name=Carved Basalt
tile.basalt.carved.desc=Polished Basalt with lines hewn through the middle.

tile.planks.oak.name=Wooden Planks
tile.planks.oak.desc=Processed tree insides.
tile.planks.oak.painted.name=Mystery Planks
tile.planks.oak.painted.desc=How did you get this?!
tile.planks.oak.painted.black.name=Black Wooden Planks
tile.planks.oak.painted.black.desc=Wooden planks, stained black.
tile.planks.oak.painted.red.name=Red Wooden Planks
tile.planks.oak.painted.red.desc=Wooden planks, stained red.
tile.planks.oak.painted.green.name=Green Wooden Planks
tile.planks.oak.painted.green.desc=Wooden planks, stained green.
tile.planks.oak.painted.brown.name=Brown Wooden Planks
tile.planks.oak.painted.brown.desc=Wooden planks, stained brown.
tile.planks.oak.painted.blue.name=Blue Wooden Planks
tile.planks.oak.painted.blue.desc=Wooden planks, stained blue.
tile.planks.oak.painted.purple.name=Purple Wooden Planks
tile.planks.oak.painted.purple.desc=Wooden planks, stained purple.
tile.planks.oak.painted.cyan.name=Cyan Wooden Planks
tile.planks.oak.painted.cyan.desc=Wooden planks, stained cyan.
tile.planks.oak.painted.silver.name=Light Gray Wooden Planks
tile.planks.oak.painted.silver.desc=Wooden planks, stained light gray.
tile.planks.oak.painted.gray.name=Gray Wooden Planks
tile.planks.oak.painted.gray.desc=Wooden planks, stained gray.
tile.planks.oak.painted.pink.name=Pink Wooden Planks
tile.planks.oak.painted.pink.desc=Wooden planks, stained pink.
tile.planks.oak.painted.lime.name=Lime Wooden Planks
tile.planks.oak.painted.lime.desc=Wooden planks, stained lime.
tile.planks.oak.painted.yellow.name=Yellow Wooden Planks
tile.planks.oak.painted.yellow.desc=Wooden planks, stained yellow.
tile.planks.oak.painted.lightblue.name=Light Blue Wooden Planks
tile.planks.oak.painted.lightblue.desc=Wooden planks, stained light blue.
tile.planks.oak.painted.magenta.name=Magenta Wooden Planks
tile.planks.oak.painted.magenta.desc=Wooden planks, stained magenta.
tile.planks.oak.painted.orange.name=Orange Wooden Planks
tile.planks.oak.painted.orange.desc=Wooden planks, stained orange.
tile.planks.oak.painted.white.name=White Wooden Planks
tile.planks.oak.painted.white.desc=Wooden planks, stained white.

tile.torch.coal.name=Torch
tile.torch.coal.desc=Helps light the way.

tile.ladder.oak.name=Oak Ladder
tile.ladder.oak.desc=For very rapid vertical movement.

tile.fence.planks.oak.name=Oak Fence
tile.fence.planks.oak.desc=Too tall to jump over.

tile.fence.planks.oak.painted.name=Mystery Wooden Fence
tile.fence.planks.oak.painted.desc=How did you get this?!
tile.fence.planks.oak.painted.black.name=Black Wooden Fence
tile.fence.planks.oak.painted.black.desc=A wooden fence, stained black.
tile.fence.planks.oak.painted.red.name=Red Wooden Fence
tile.fence.planks.oak.painted.red.desc=A wooden fence, stained red.
tile.fence.planks.oak.painted.green.name=Green Wooden Fence
tile.fence.planks.oak.painted.green.desc=A wooden fence, stained green.
tile.fence.planks.oak.painted.brown.name=Brown Wooden Fence
tile.fence.planks.oak.painted.brown.desc=A wooden fence, stained brown.
tile.fence.planks.oak.painted.blue.name=Blue Wooden Fence
tile.fence.planks.oak.painted.blue.desc=A wooden fence, stained blue.
tile.fence.planks.oak.painted.purple.name=Purple Wooden Fence
tile.fence.planks.oak.painted.purple.desc=A wooden fence, stained purple.
tile.fence.planks.oak.painted.cyan.name=Cyan Wooden Fence
tile.fence.planks.oak.painted.cyan.desc=A wooden fence, stained cyan.
tile.fence.planks.oak.painted.silver.name=Light Gray Wooden Fence
tile.fence.planks.oak.painted.silver.desc=A wooden fence, stained light gray.
tile.fence.planks.oak.painted.gray.name=Gray Wooden Fence
tile.fence.planks.oak.painted.gray.desc=A wooden fence, stained gray.
tile.fence.planks.oak.painted.pink.name=Pink Wooden Fence
tile.fence.planks.oak.painted.pink.desc=A wooden fence, stained pink.
tile.fence.planks.oak.painted.lime.name=Lime Wooden Fence
tile.fence.planks.oak.painted.lime.desc=A wooden fence, stained lime.
tile.fence.planks.oak.painted.yellow.name=Yellow Wooden Fence
tile.fence.planks.oak.painted.yellow.desc=A wooden fence, stained yellow.
tile.fence.planks.oak.painted.lightblue.name=Light Blue Wooden Fence
tile.fence.planks.oak.painted.lightblue.desc=A wooden fence, stained light blue.
tile.fence.planks.oak.painted.magenta.name=Magenta Wooden Fence
tile.fence.planks.oak.painted.magenta.desc=A wooden fence, stained magenta.
tile.fence.planks.oak.painted.orange.name=Orange Wooden Fence
tile.fence.planks.oak.painted.orange.desc=A wooden fence, stained orange.
tile.fence.planks.oak.painted.white.name=White Wooden Fence
tile.fence.planks.oak.painted.white.desc=A wooden fence, stained white.

tile.fencegate.planks.oak.name=Wooden Fence Gate
tile.fencegate.planks.oak.desc=Like a door but for fences.

tile.fencegate.planks.oak.painted.name=Mystery Wooden Fence Gate
tile.fencegate.planks.oak.painted.desc=How did you get this?!
tile.fencegate.planks.oak.painted.black.name=Black Wooden Fence Gate
tile.fencegate.planks.oak.painted.black.desc=A wooden fence gate, stained black.
tile.fencegate.planks.oak.painted.red.name=Red Wooden Fence Gate
tile.fencegate.planks.oak.painted.red.desc=A wooden fence gate, stained red.
tile.fencegate.planks.oak.painted.green.name=Green Wooden Fence Gate
tile.fencegate.planks.oak.painted.green.desc=A wooden fence gate, stained green.
tile.fencegate.planks.oak.painted.brown.name=Brown Wooden Fence Gate
tile.fencegate.planks.oak.painted.brown.desc=A wooden fence gate, stained brown.
tile.fencegate.planks.oak.painted.blue.name=Blue Wooden Fence Gate
tile.fencegate.planks.oak.painted.blue.desc=A wooden fence gate, stained blue.
tile.fencegate.planks.oak.painted.purple.name=Purple Wooden Fence Gate
tile.fencegate.planks.oak.painted.purple.desc=A wooden fence gate, stained purple.
tile.fencegate.planks.oak.painted.cyan.name=Cyan Wooden Fence Gate
tile.fencegate.planks.oak.painted.cyan.desc=A wooden fence gate, stained cyan.
tile.fencegate.planks.oak.painted.silver.name=Light Gray Wooden Fence Gate
tile.fencegate.planks.oak.painted.silver.desc=A wooden fence gate, stained light gray.
tile.fencegate.planks.oak.painted.gray.name=Gray Wooden Fence Gate
tile.fencegate.planks.oak.painted.gray.desc=A wooden fence gate, stained gray.
tile.fencegate.planks.oak.painted.pink.name=Pink Wooden Fence Gate
tile.fencegate.planks.oak.painted.pink.desc=A wooden fence gate, stained pink.
tile.fencegate.planks.oak.painted.lime.name=Lime Wooden Fence Gate
tile.fencegate.planks.oak.painted.lime.desc=A wooden fence gate, stained lime.
tile.fencegate.planks.oak.painted.yellow.name=Yellow Wooden Fence Gate
tile.fencegate.planks.oak.painted.yellow.desc=A wooden fence gate, stained yellow.
tile.fencegate.planks.oak.painted.lightblue.name=Light Blue Wooden Fence Gate
tile.fencegate.planks.oak.painted.lightblue.desc=A wooden fence gate, stained light blue.
tile.fencegate.planks.oak.painted.magenta.name=Magenta Wooden Fence Gate
tile.fencegate.planks.oak.painted.magenta.desc=A wooden fence gate, stained magenta.
tile.fencegate.planks.oak.painted.orange.name=Orange Wooden Fence Gate
tile.fencegate.planks.oak.painted.orange.desc=A wooden fence gate, stained orange.
tile.fencegate.planks.oak.painted.white.name=White Wooden Fence Gate
tile.fencegate.planks.oak.painted.white.desc=A wooden fence gate, stained white.

tile.bookshelf.planks.oak.name=Bookshelf
tile.bookshelf.planks.oak.desc=A repository of knowledge.

tile.wool.name=Wool
tile.wool.desc=How did you get this?!
tile.wool.black.name=Black Wool
tile.wool.black.desc=Sheep's wool, dyed black.
tile.wool.red.name=Red Wool
tile.wool.red.desc=Sheep's wool, dyed red.
tile.wool.green.name=Green Wool
tile.wool.green.desc=Sheep's wool, dyed green.
tile.wool.brown.name=Brown Wool
tile.wool.brown.desc=Sheep's wool, dyed brown.
tile.wool.blue.name=Blue Wool
tile.wool.blue.desc=Sheep's wool, dyed blue.
tile.wool.purple.name=Purple Wool
tile.wool.purple.desc=Sheep's wool, dyed purple.
tile.wool.cyan.name=Cyan Wool
tile.wool.cyan.desc=Sheep's wool, dyed cyan.
tile.wool.silver.name=Light Gray Wool
tile.wool.silver.desc=Sheep's wool, dyed light gray.
tile.wool.gray.name=Gray Wool
tile.wool.gray.desc=Sheep's wool, dyed gray.
tile.wool.pink.name=Pink Wool
tile.wool.pink.desc=Sheep's wool, dyed pink.
tile.wool.lime.name=Lime Wool
tile.wool.lime.desc=Sheep's wool, dyed lime.
tile.wool.yellow.name=Yellow Wool
tile.wool.yellow.desc=Sheep's wool, dyed yellow.
tile.wool.lightblue.name=Light Blue Wool
tile.wool.lightblue.desc=Sheep's wool, dyed light blue.
tile.wool.magenta.name=Magenta Wool
tile.wool.magenta.desc=Sheep's wool, dyed magenta.
tile.wool.orange.name=Orange Wool
tile.wool.orange.desc=Sheep's wool, dyed orange.
tile.wool.white.name=White Wool
tile.wool.white.desc=Sheep's wool, dyed white.

tile.brick.clay.name=Clay Bricks
tile.brick.clay.desc=Stacked bricks of baked clay.
tile.brick.stone.polished.name=Polished Stone Bricks
tile.brick.stone.polished.desc=Stacked bricks of polished stone.
tile.brick.stone.polished.mossy.name=Mossy Polished Stone Bricks
tile.brick.stone.polished.mossy.desc=Stacked bricks of polished stone with added greenery.
tile.brick.sandstone.name=Sandstone Bricks
tile.brick.sandstone.desc=Stacked bricks of sandstone.
tile.brick.gold.name=Gold Bricks
tile.brick.gold.desc=Stacked bricks of gold.
tile.brick.lapis.name=Lapis Lazuli Bricks
tile.brick.lapis.desc=Stacked bricks of lapis lazuli.
tile.brick.basalt.name=Basalt Bricks
tile.brick.basalt.desc=Stacked bricks of basalt.
tile.brick.limestone.name=Limestone Bricks
tile.brick.limestone.desc=Stacked bricks of limestone.
tile.brick.granite.name=Granite Bricks
tile.brick.granite.desc=Stacked bricks of granite.
tile.brick.marble.name=Marble Bricks
tile.brick.marble.desc=Stacked bricks of marble.
tile.brick.slate.name=Slate Bricks
tile.brick.slate.desc=Stacked bricks of slate.
tile.brick.stone.name=Stone Bricks
tile.brick.stone.desc=Stacked bricks of stone.
tile.brick.permafrost.name=Permafrost Bricks
tile.brick.permafrost.desc=Stacked bricks of permafrost.
tile.brick.iron.name=Iron Bricks
tile.brick.iron.desc=Stacked bricks of iron.

tile.slab.planks.oak.name=Wooden Slab
tile.slab.planks.oak.desc=A slab of wooden planks.
tile.slab.cobble.stone.name=Cobblestone Slab
tile.slab.cobble.stone.desc=A slab of cobblestone.
tile.slab.sandstone.name=Sandstone Slab
tile.slab.sandstone.desc=A slab of sandstone.
tile.slab.brick.stone.polished.name=Polished Stone Brick Slab
tile.slab.brick.stone.polished.desc=A slab of polished stone bricks.
tile.slab.stone.carved.name=Polished Stone Slab
tile.slab.stone.carved.desc=A slab of polished stone.
tile.slab.brick.marble.name=Marble Brick Slab
tile.slab.brick.marble.desc=A slab of marble bricks.
tile.slab.brick.clay.name=Clay Brick Slab
tile.slab.brick.clay.desc=A slab of clay bricks.
tile.slab.capstone.marble.name=Marble Capstone Slab
tile.slab.capstone.marble.desc=Marble sculpted into a capstone.
tile.slab.cobble.basalt.name=Cobbled Basalt Slab
tile.slab.cobble.basalt.desc=A slab of cobbled basalt.
tile.slab.cobble.limestone.name=Cobbled Limestone Slab
tile.slab.cobble.limestone.desc=A slab of cobbled limestone.
tile.slab.cobble.granite.name=Cobbled Granite Slab
tile.slab.cobble.granite.desc=A slab of cobbled granite.
tile.slab.brick.basalt.name=Basalt Brick Slab
tile.slab.brick.basalt.desc=A slab of basalt bricks.
tile.slab.brick.limestone.name=Limestone Brick Slab
tile.slab.brick.limestone.desc=A slab of limestone bricks.
tile.slab.brick.granite.name=Granite Brick Slab
tile.slab.brick.granite.desc=A slab of granite bricks.
tile.slab.brick.slate.name=Slate Brick Slab
tile.slab.brick.slate.desc=A slab of slate bricks.
tile.slab.brick.stone.name=Stone Brick Slab
tile.slab.brick.stone.desc=A slab of stone bricks.
tile.slab.granite.carved.name=Polished Granite Slab
tile.slab.granite.carved.desc=A slab of polished granite.
tile.slab.limestone.carved.name=Polished Limestone Slab
tile.slab.limestone.carved.desc=A slab of polished limestone.
tile.slab.basalt.carved.name=Polished Basalt Slab
tile.slab.basalt.carved.desc=A slab of polished basalt.

tile.slab.planks.oak.painted.name=Mystery Wooden Slab
tile.slab.planks.oak.painted.desc=How did you get this?!
tile.slab.planks.oak.painted.black.name=Black Wooden Slab
tile.slab.planks.oak.painted.black.desc=A slab of wooden planks, stained black.
tile.slab.planks.oak.painted.red.name=Red Wooden Slab
tile.slab.planks.oak.painted.red.desc=A slab of wooden planks, stained red.
tile.slab.planks.oak.painted.green.name=Green Wooden Slab
tile.slab.planks.oak.painted.green.desc=A slab of wooden planks, stained green.
tile.slab.planks.oak.painted.brown.name=Brown Wooden Slab
tile.slab.planks.oak.painted.brown.desc=A slab of wooden planks, stained brown.
tile.slab.planks.oak.painted.blue.name=Blue Wooden Slab
tile.slab.planks.oak.painted.blue.desc=A slab of wooden planks, stained blue.
tile.slab.planks.oak.painted.purple.name=Purple Wooden Slab
tile.slab.planks.oak.painted.purple.desc=A slab of wooden planks, stained purple.
tile.slab.planks.oak.painted.cyan.name=Cyan Wooden Slab
tile.slab.planks.oak.painted.cyan.desc=A slab of wooden planks, stained cyan.
tile.slab.planks.oak.painted.silver.name=Light Gray Wooden Slab
tile.slab.planks.oak.painted.silver.desc=A slab of wooden planks, stained light gray.
tile.slab.planks.oak.painted.gray.name=Gray Wooden Slab
tile.slab.planks.oak.painted.gray.desc=A slab of wooden planks, stained gray.
tile.slab.planks.oak.painted.pink.name=Pink Wooden Slab
tile.slab.planks.oak.painted.pink.desc=A slab of wooden planks, stained pink.
tile.slab.planks.oak.painted.lime.name=Lime Wooden Slab
tile.slab.planks.oak.painted.lime.desc=A slab of wooden planks, stained lime.
tile.slab.planks.oak.painted.yellow.name=Yellow Wooden Slab
tile.slab.planks.oak.painted.yellow.desc=A slab of wooden planks, stained yellow.
tile.slab.planks.oak.painted.lightblue.name=Light Blue Wooden Slab
tile.slab.planks.oak.painted.lightblue.desc=A slab of wooden planks, stained light blue.
tile.slab.planks.oak.painted.magenta.name=Magenta Wooden Slab
tile.slab.planks.oak.painted.magenta.desc=A slab of wooden planks, stained magenta.
tile.slab.planks.oak.painted.orange.name=Orange Wooden Slab
tile.slab.planks.oak.painted.orange.desc=A slab of wooden planks, stained orange.
tile.slab.planks.oak.painted.white.name=White Wooden Slab
tile.slab.planks.oak.painted.white.desc=A slab of wooden planks, stained white.

tile.stairs.planks.oak.name=Wooden Stairs
tile.stairs.planks.oak.desc=Wooden block used for rapid vertical movement.
tile.stairs.cobble.stone.name=Cobblestone Stairs
tile.stairs.cobble.stone.desc=Cobblestone block used for rapid vertical movement.
tile.stairs.brick.stone.polished.name=Polished Stone Brick Stairs
tile.stairs.brick.stone.polished.desc=Polished stone brick block used for rapid vertical movement.
tile.stairs.brick.marble.name=Marble Brick Stairs
tile.stairs.brick.marble.desc=Marble brick block used for rapid vertical movement.
tile.stairs.cobble.basalt.name=Cobbled Basalt Stairs
tile.stairs.cobble.basalt.desc=Cobbled basalt block used for rapid vertical movement.
tile.stairs.cobble.limestone.name=Cobbled Limestone Stairs
tile.stairs.cobble.limestone.desc=Cobbled limestone block used for rapid vertical movement.
tile.stairs.cobble.granite.name=Cobbled Granite Stairs
tile.stairs.cobble.granite.desc=Cobbled granite block used for rapid vertical movement.
tile.stairs.brick.basalt.name=Basalt Brick Stairs
tile.stairs.brick.basalt.desc=Basalt brick block used for rapid vertical movement.
tile.stairs.brick.limestone.name=Limestone Brick Stairs
tile.stairs.brick.limestone.desc=Limestone brick block used for rapid vertical movement.
tile.stairs.brick.granite.name=Granite Brick Stairs
tile.stairs.brick.granite.desc=Granite brick block used for rapid vertical movement.
tile.stairs.brick.clay.name=Clay Brick Stairs
tile.stairs.brick.clay.desc=Clay brick block used for rapid vertical movement.
tile.stairs.brick.slate.name=Slate Brick Stairs
tile.stairs.brick.slate.desc=Slate brick block used for rapid vertical movement.
tile.stairs.brick.stone.name=Stone Brick Stairs
tile.stairs.brick.stone.desc=Stone brick block used for rapid vertical movement.

tile.stairs.planks.oak.painted.name=Mystery Wooden Stairs
tile.stairs.planks.oak.painted.desc=How did you get this?!
tile.stairs.planks.oak.painted.black.name=Black Wooden Stairs
tile.stairs.planks.oak.painted.black.desc=Wooden steps, stained black.
tile.stairs.planks.oak.painted.red.name=Red Wooden Stairs
tile.stairs.planks.oak.painted.red.desc=Wooden steps, stained red.
tile.stairs.planks.oak.painted.green.name=Green Wooden Stairs
tile.stairs.planks.oak.painted.green.desc=Wooden steps, stained green.
tile.stairs.planks.oak.painted.brown.name=Brown Wooden Stairs
tile.stairs.planks.oak.painted.brown.desc=Wooden steps, stained brown.
tile.stairs.planks.oak.painted.blue.name=Blue Wooden Stairs
tile.stairs.planks.oak.painted.blue.desc=Wooden steps, stained blue.
tile.stairs.planks.oak.painted.purple.name=Purple Wooden Stairs
tile.stairs.planks.oak.painted.purple.desc=Wooden steps, stained purple.
tile.stairs.planks.oak.painted.cyan.name=Cyan Wooden Stairs
tile.stairs.planks.oak.painted.cyan.desc=Wooden steps, stained cyan.
tile.stairs.planks.oak.painted.silver.name=Light Gray Wooden Stairs
tile.stairs.planks.oak.painted.silver.desc=Wooden steps, stained light gray.
tile.stairs.planks.oak.painted.gray.name=Gray Wooden Stairs
tile.stairs.planks.oak.painted.gray.desc=Wooden steps, stained gray.
tile.stairs.planks.oak.painted.pink.name=Pink Wooden Stairs
tile.stairs.planks.oak.painted.pink.desc=Wooden steps, stained pink.
tile.stairs.planks.oak.painted.lime.name=Lime Wooden Stairs
tile.stairs.planks.oak.painted.lime.desc=Wooden steps, stained lime.
tile.stairs.planks.oak.painted.yellow.name=Yellow Wooden Stairs
tile.stairs.planks.oak.painted.yellow.desc=Wooden steps, stained yellow.
tile.stairs.planks.oak.painted.lightblue.name=Light Blue Wooden Stairs
tile.stairs.planks.oak.painted.lightblue.desc=Wooden steps, stained light blue.
tile.stairs.planks.oak.painted.magenta.name=Magenta Wooden Stairs
tile.stairs.planks.oak.painted.magenta.desc=Wooden steps, stained magenta.
tile.stairs.planks.oak.painted.orange.name=Orange Wooden Stairs
tile.stairs.planks.oak.painted.orange.desc=Wooden steps, stained orange.
tile.stairs.planks.oak.painted.white.name=White Wooden Stairs
tile.stairs.planks.oak.painted.white.desc=Wooden steps, stained white.

tile.obsidian.name=Obsidian
tile.obsidian.desc=Rapidly cooled volcanic rock.

tile.glass.name=Glass
tile.glass.desc=Sand heated until it becomes translucent.
tile.glass.tinted.name=Tinted Glass
tile.glass.tinted.desc=Darkened glass that blocks light.

tile.grass.name=Grass
tile.grass.desc=Crisp, crunchy grass.
tile.grass.retro.name=Retro Grass
tile.grass.retro.desc=Crisp, crunchy grass. Smells old.
tile.grass.scorched.name=Scorched Grass
tile.grass.scorched.desc=Grass that has baked in the sun.

tile.path.dirt.name=Dirt Path
tile.path.dirt.desc=Dirt worn down by frequent travelling.

tile.dirt.name=Dirt
tile.dirt.desc=Crumbly brown dirt.
tile.dirt.scorched.name=Scorched Dirt
tile.dirt.scorched.desc=Dirt that has baked in the sun.
tile.dirt.scorched.rich.name=Rich Scorched Dirt
tile.dirt.scorched.rich.desc=Dirt that has baked in the sun, searing in minerals.

tile.mud.name=Mud
tile.mud.desc=Mud sodden to its core.
tile.mud.baked.name=Baked Mud
tile.mud.baked.desc=Mud that's been dried out and cracked.

tile.sponge.dry.name=Sponge
tile.sponge.dry.desc=A dry sponge, good for soaking up water.
tile.sponge.wet.name=Wet Sponge
tile.sponge.wet.desc=A sponge full of water.

tile.moss.stone.name=Mossy Stone
tile.moss.stone.desc=Moss covering a block of stone.
tile.moss.basalt.name=Mossy Basalt
tile.moss.basalt.desc=Moss covering a block of basalt.
tile.moss.limestone.name=Mossy Limestone
tile.moss.limestone.desc=Moss covering a block of limestone.
tile.moss.granite.name=Mossy Granite
tile.moss.granite.desc=Moss covering a block of granite.

tile.sand.name=Sand
tile.sand.desc=Gets everywhere.
tile.gravel.name=Gravel
tile.gravel.desc=A loose collection of pebbles.

tile.bedrock.name=Bedrock
tile.bedrock.desc=The toughest substance known to man.

tile.fluid.water.flowing.name=Flowing Water
tile.fluid.water.flowing.desc=Water that flows when placed.
tile.fluid.water.still.name=Still Water
tile.fluid.water.still.desc=Water that does not flow when placed.
tile.fluid.lava.flowing.name=Flowing Lava
tile.fluid.lava.flowing.desc=Lava that flows when placed.
tile.fluid.lava.still.name=Still Lava
tile.fluid.lava.still.desc=Lava that does not flow when placed.

tile.log.oak.name=Oak Log
tile.log.oak.desc=A log from an oak tree.
tile.log.pine.name=Pine Log
tile.log.pine.desc=A log from a pine tree.
tile.log.birch.name=Birch Log
tile.log.birch.desc=A log from a birch tree.
tile.log.cherry.name=Cherry Log
tile.log.cherry.desc=A log from a cherry tree.
tile.log.eucalyptus.name=Eucalyptus Log
tile.log.eucalyptus.desc=A log from a eucalyptus tree.
tile.log.oak.mossy.name=Mossy Oak Log
tile.log.oak.mossy.desc=A log from a mossy oak tree.

tile.leaves.oak.name=Oak Leaves
tile.leaves.oak.desc=Leaves from an oak tree.
tile.leaves.pine.name=Pine Leaves
tile.leaves.pine.desc=Leaves from a pine tree.
tile.leaves.birch.name=Birch Leaves
tile.leaves.birch.desc=Leaves from a birch tree.
tile.leaves.cherry.name=Cherry Leaves
tile.leaves.cherry.desc=Leaves from a cherry tree.
tile.leaves.eucalyptus.name=Eucalyptus Leaves
tile.leaves.eucalyptus.desc=Leaves from a eucalyptus tree.
tile.leaves.oak.retro.name=Retro Leaves
tile.leaves.oak.retro.desc=Leaves from long ago.
tile.leaves.shrub.name=Shrub Leaves
tile.leaves.shrub.desc=Leaves from a shrub.
tile.leaves.cherry.flowering.name=Flowering Cherry Leaves
tile.leaves.cherry.flowering.desc=Leaves from a cherry tree that are budding with fruit.
tile.leaves.cacao.name=Cacao Leaves
tile.leaves.cacao.desc=Leaves from a cacao tree.
tile.leaves.caatinga.name=Caatinga Leaves
tile.leaves.caatinga.desc=Leaves from a caatinga tree.

tile.sapling.oak.name=Oak Sapling
tile.sapling.oak.desc=Plant to grow an oak tree.
tile.sapling.pine.name=Pine Sapling
tile.sapling.pine.desc=Plant to grow a pine tree.
tile.sapling.birch.name=Birch Sapling
tile.sapling.birch.desc=Plant to grow a birch tree.
tile.sapling.cherry.name=Cherry Sapling
tile.sapling.cherry.desc=Plant to grow a cherry tree.
tile.sapling.eucalyptus.name=Eucalyptus Sapling
tile.sapling.eucalyptus.desc=Plant to grow a eucalyptus tree.
tile.sapling.oak.retro.name=Retro Oak Sapling
tile.sapling.oak.retro.desc=Plant to grow a tree from long ago.
tile.sapling.shrub.name=Shrub Sapling
tile.sapling.shrub.desc=Plant to grow a shrub.
tile.sapling.cacao.name=Cacao Sapling
tile.sapling.cacao.desc=Plant to grow a cacao tree.

tile.tallgrass.name=Tall Grass
tile.tallgrass.desc=Lush, growing grass.
tile.tallgrass.fern.name=Fern
tile.tallgrass.fern.desc=A fern plant.
tile.deadbush.name=Dead Bush
tile.deadbush.desc=A dried and withered plant.
tile.spinifex.name=Spinifex
tile.spinifex.desc=A spindly, thin grass from dry regions.
tile.algae.name=Algae
tile.algae.desc=Gooey vegetation that floats on the water's surface.

tile.flower.yellow.name=Dandelion
tile.flower.yellow.desc=A beautiful yellow flower.
tile.flower.red.name=Rose
tile.flower.red.desc=A beautiful red flower.
tile.flower.purple.name=Heather
tile.flower.purple.desc=Sprigs of purple petals. Brings good luck.
tile.flower.lightblue.name=Bluebell
tile.flower.lightblue.desc=A sad-looking blue flower.
tile.flower.pink.name=Orchid
tile.flower.pink.desc=A beautiful pink flower.

tile.mushroom.red.name=Red Mushroom
tile.mushroom.red.desc=A tasty red mushroom. Good for stew.
tile.mushroom.brown.name=Brown Mushroom
tile.mushroom.brown.desc=A tasty brown mushroom. Good for stew.

tile.ore.coal.stone.name=Stone Coal Ore
tile.ore.coal.stone.desc=A chunk of coal embedded in stone.
tile.ore.coal.basalt.name=Basalt Coal Ore
tile.ore.coal.basalt.desc=A chunk of coal embedded in basalt.
tile.ore.coal.limestone.name=Limestone Coal Ore
tile.ore.coal.limestone.desc=A chunk of coal embedded in limestone.
tile.ore.coal.granite.name=Granite Coal Ore
tile.ore.coal.granite.desc=A chunk of coal embedded in granite.

tile.ore.iron.stone.name=Stone Iron Ore
tile.ore.iron.stone.desc=Iron nuggets embedded in stone.
tile.ore.iron.basalt.name=Basalt Iron Ore
tile.ore.iron.basalt.desc=Iron nuggets embedded in basalt.
tile.ore.iron.limestone.name=Limestone Iron Ore
tile.ore.iron.limestone.desc=Iron nuggets embedded in limestone.
tile.ore.iron.granite.name=Granite Iron Ore
tile.ore.iron.granite.desc=Iron nuggets embedded in granite.

tile.ore.gold.stone.name=Stone Gold Ore
tile.ore.gold.stone.desc=Gold nuggets embedded in stone.
tile.ore.gold.basalt.name=Basalt Gold Ore
tile.ore.gold.basalt.desc=Gold nuggets embedded in basalt.
tile.ore.gold.limestone.name=Limestone Gold Ore
tile.ore.gold.limestone.desc=Gold nuggets embedded in limestone.
tile.ore.gold.granite.name=Granite Gold Ore
tile.ore.gold.granite.desc=Gold nuggets embedded in granite.

tile.ore.lapis.stone.name=Stone Lapis Lazuli Ore
tile.ore.lapis.stone.desc=Chunks of lapis lazuli embedded in stone.
tile.ore.lapis.basalt.name=Basalt Lapis Lazuli Ore
tile.ore.lapis.basalt.desc=Chunks of lapis lazuli embedded in basalt.
tile.ore.lapis.limestone.name=Limestone Lapis Lazuli Ore
tile.ore.lapis.limestone.desc=Chunks of lapis lazuli embedded in limestone.
tile.ore.lapis.granite.name=Granite Lapis Lazuli Ore
tile.ore.lapis.granite.desc=Chunks of lapis lazuli embedded in granite.

tile.ore.redstone.stone.name=Stone Redstone Ore
tile.ore.redstone.stone.desc=Red dust embedded in stone.
tile.ore.redstone.basalt.name=Basalt Redstone Ore
tile.ore.redstone.basalt.desc=Red dust embedded in basalt.
tile.ore.redstone.limestone.name=Limestone Redstone Ore
tile.ore.redstone.limestone.desc=Red dust embedded in limestone.
tile.ore.redstone.granite.name=Granite Redstone Ore
tile.ore.redstone.granite.desc=Red dust embedded in granite.
tile.ore.redstone.glowing.stone.name=Glowing Stone Redstone Ore
tile.ore.redstone.glowing.stone.desc=Red dust embedded in stone. Emits a faint light.
tile.ore.redstone.glowing.basalt.name=Glowing Basalt Redstone Ore
tile.ore.redstone.glowing.basalt.desc=Red dust embedded in basalt. Emits a faint light.
tile.ore.redstone.glowing.limestone.name=Glowing Limestone Redstone Ore
tile.ore.redstone.glowing.limestone.desc=Red dust embedded in limestone. Emits a faint light.
tile.ore.redstone.glowing.granite.name=Glowing Granite Redstone Ore
tile.ore.redstone.glowing.granite.desc=Red dust embedded in granite. Emits a faint light.

tile.ore.diamond.stone.name=Stone Diamond Ore
tile.ore.diamond.stone.desc=A chunk of diamond embedded in stone.
tile.ore.diamond.basalt.name=Basalt Diamond Ore
tile.ore.diamond.basalt.desc=A chunk of diamond embedded in basalt.
tile.ore.diamond.limestone.name=Limestone Diamond Ore
tile.ore.diamond.limestone.desc=A chunk of diamond embedded in limestone.
tile.ore.diamond.granite.name=Granite Diamond Ore
tile.ore.diamond.granite.desc=A chunk of diamond embedded in granite.

tile.ore.nethercoal.netherrack.name=Nether Coal Ore
tile.ore.nethercoal.netherrack.desc=A lump of Nether Coal embedded in netherrack.

tile.block.coal.name=Block of Coal
tile.block.coal.desc=A solid block of coal.
tile.block.iron.name=Block of Iron
tile.block.iron.desc=A solid block of iron. Heavy!
tile.block.gold.name=Block of Gold
tile.block.gold.desc=A solid block of gold, for flaunting your bling.
tile.block.lapis.name=Block of Lapis Lazuli
tile.block.lapis.desc=A solid block of lapis lazuli.
tile.block.redstone.name=Block of Redstone
tile.block.redstone.desc=A solid block of redstone.
tile.block.diamond.name=Block of Diamond
tile.block.diamond.desc=A solid block of diamond. Well done you.
tile.block.nethercoal.name=Block of Nether Coal
tile.block.nethercoal.desc=A solid block of Nether Coal.
tile.block.steel.name=Block of Steel
tile.block.steel.desc=A solid block of steel.
tile.block.quartz.name=Block of Quartz
tile.block.quartz.desc=A solid block of quartz.
tile.block.olivine.name=Block of Olivine
tile.block.olivine.desc=A solid block of olivine.
tile.block.charcoal.name=Block of Charcoal
tile.block.charcoal.desc=A solid block of charcoal.

tile.wire.redstone.name=Redstone Wire
tile.wire.redstone.desc=A strand of redstone dust laid on the ground.

tile.torch.redstone.idle.name=Redstone Torch
tile.torch.redstone.idle.desc=Emits a constant redstone signal.
tile.torch.redstone.active.name=Redstone Torch
tile.torch.redstone.active.desc=Emits a constant redstone signal.

tile.button.stone.name=Stone Button
tile.button.stone.desc=Emits a brief redstone signal when pressed.

tile.lever.cobble.stone.name=Cobblestone Lever
tile.lever.cobble.stone.desc=Allows turning a redstone signal on or off.

tile.pressureplate.stone.name=Stone Pressure Plate
tile.pressureplate.stone.desc=Emits a redstone signal when living creatures step on it.
tile.pressureplate.planks.oak.name=Wooden Pressure Plate
tile.pressureplate.planks.oak.desc=Emits a redstone signal when anything steps on it.
tile.pressureplate.cobble.stone.name=Cobblestone Pressure Plate
tile.pressureplate.cobble.stone.desc=Emits a redstone signal when players step on it.

tile.motionsensor.idle.name=Motion Sensor
tile.motionsensor.idle.desc=Emits a redstone signal when something moves past it.
tile.motionsensor.active.name=Active Motion Sensor
tile.motionsensor.active.desc=Emits a redstone signal when something moves past it.

tile.repeater.idle.name=Redstone Repeater
tile.repeater.idle.desc=Repeats redstone signals over a distance.
tile.repeater.active.name=Redstone Repeater
tile.repeater.active.desc=Repeats redstone signals over a distance.

tile.piston.base.name=Piston
tile.piston.base.desc=Pushes blocks but does not pull them.
tile.piston.base.sticky.name=Sticky Piston
tile.piston.base.sticky.desc=Pushes and pulls blocks.
tile.piston.head.name=Piston Head
tile.piston.head.desc=The pushy part of the piston.
tile.piston.moving.name=Piston Mover
tile.piston.moving.desc=The invisible moving part of the piston.

tile.noteblock.name=Note Block
tile.noteblock.desc=Plays a musical note when powered.

tile.rail.name=Rail
tile.rail.desc=For rapid horizontal movement via minecart.
tile.rail.powered.name=Powered Rail
tile.rail.powered.desc=Makes minecarts go faster when powered.
tile.rail.detector.name=Detector Rail
tile.rail.detector.desc=Emits a redstone signal when a minecart crosses it.

tile.spikes.name=Spike Trap
tile.spikes.desc=Deactivates when powered. Technically a war crime.

tile.dispenser.cobble.stone.name=Dispenser
tile.dispenser.cobble.stone.desc=Fires items out of the hole in the front.

tile.trapdoor.planks.oak.name=Oak Trapdoor
tile.trapdoor.planks.oak.desc=Like a door, but flat.
tile.trapdoor.iron.name=Iron Trapdoor
tile.trapdoor.iron.desc=Like a door, but flat and made of iron.
tile.trapdoor.glass.name=Glass Trapdoor
tile.trapdoor.glass.desc=Useless at its job.

tile.tnt.name=TNT
tile.tnt.desc=Goes off with a bang.

tile.door.planks.oak.bottom.name=Bottom Wooden Door
tile.door.planks.oak.bottom.desc=/give Honeydew 64 46
tile.door.planks.oak.top.name=Top Wooden Door
tile.door.planks.oak.top.desc=Oh, wait, that's not TNT, that's half a door.
tile.door.iron.bottom.name=Bottom Iron Door
tile.door.iron.bottom.desc=Not much good on its own.
tile.door.iron.top.name=Top Iron Door
tile.door.iron.top.desc=Could use a friend.

tile.mesh.name=Mesh Block
tile.mesh.desc=Allows items to pass through but nothing else.
tile.mesh.gold.name=Gold Mesh Block
tile.mesh.gold.desc=Allows a specified item to pass through but nothing else.

tile.bed.name=Bed
tile.bed.desc=Bed!
tile.seat.name=Seat
tile.seat.desc=Sit down and relax.

tile.cobweb.name=Cobweb
tile.cobweb.desc=Sticky silky strands woven by spiders.

tile.fire.name=Fire
tile.fire.desc=Ouch, fire hot!
tile.brazier.inactive.name=Brazier
tile.brazier.inactive.desc=A safe place to keep a fire.
tile.brazier.active.name=Lit Brazier
tile.brazier.active.desc=A safe place to keep a fire.

tile.mobspawner.name=Mob Spawner
tile.mobspawner.desc=A cage filled with horror.
tile.mobspawner.deactivated.name=Deactivated Mob Spawner
tile.mobspawner.deactivated.desc=A cage no longer filled with horror.

tile.workbench.name=Workbench
tile.workbench.desc=For bigger projects.

tile.furnace.stone.idle.name=Furnace
tile.furnace.stone.idle.desc=For melting, heating, and cooking blocks and items.
tile.furnace.stone.active.name=Lit Furnace
tile.furnace.stone.active.desc=For melting, heating, and cooking blocks and items.
tile.furnace.blast.idle.name=Blast Furnace
tile.furnace.blast.idle.desc=Burns hotter than a normal furnace.
tile.furnace.blast.active.name=Lit Blast Furnace
tile.furnace.blast.active.desc=Burns hotter than a normal furnace.

tile.trommel.idle.name=Trommel
tile.trommel.idle.desc=A machine that separates dirt from other useful items.
tile.trommel.active.name=Lit Trommel
tile.trommel.active.desc=A machine that separates dirt from other useful items.

tile.chest.planks.oak.name=Wooden Chest
tile.chest.planks.oak.desc=A place to store your items.
tile.chest.planks.oak.painted.name=Mystery Wooden Chest
tile.chest.planks.oak.painted.desc=How did you get this?!
tile.chest.planks.oak.painted.black.name=Black Wooden Chest
tile.chest.planks.oak.painted.black.desc=A place to store your items.
tile.chest.planks.oak.painted.red.name=Red Wooden Chest
tile.chest.planks.oak.painted.red.desc=A place to store your items.
tile.chest.planks.oak.painted.green.name=Green Wooden Chest
tile.chest.planks.oak.painted.green.desc=A place to store your items.
tile.chest.planks.oak.painted.brown.name=Brown Wooden Chest
tile.chest.planks.oak.painted.brown.desc=A place to store your items.
tile.chest.planks.oak.painted.blue.name=Blue Wooden Chest
tile.chest.planks.oak.painted.blue.desc=A place to store your items.
tile.chest.planks.oak.painted.purple.name=Purple Wooden Chest
tile.chest.planks.oak.painted.purple.desc=A place to store your items.
tile.chest.planks.oak.painted.cyan.name=Cyan Wooden Chest
tile.chest.planks.oak.painted.cyan.desc=A place to store your items.
tile.chest.planks.oak.painted.silver.name=Light Gray Wooden Chest
tile.chest.planks.oak.painted.silver.desc=A place to store your items.
tile.chest.planks.oak.painted.gray.name=Gray Wooden Chest
tile.chest.planks.oak.painted.gray.desc=A place to store your items.
tile.chest.planks.oak.painted.pink.name=Pink Wooden Chest
tile.chest.planks.oak.painted.pink.desc=A place to store your items.
tile.chest.planks.oak.painted.lime.name=Lime Wooden Chest
tile.chest.planks.oak.painted.lime.desc=A place to store your items.
tile.chest.planks.oak.painted.yellow.name=Yellow Wooden Chest
tile.chest.planks.oak.painted.yellow.desc=A place to store your items.
tile.chest.planks.oak.painted.lightblue.name=Light Blue Wooden Chest
tile.chest.planks.oak.painted.lightblue.desc=A place to store your items.
tile.chest.planks.oak.painted.magenta.name=Magenta Wooden Chest
tile.chest.planks.oak.painted.magenta.desc=A place to store your items.
tile.chest.planks.oak.painted.orange.name=Orange Wooden Chest
tile.chest.planks.oak.painted.orange.desc=A place to store your items.
tile.chest.planks.oak.painted.white.name=White Wooden Chest
tile.chest.planks.oak.painted.white.desc=A place to store your items.
tile.chest.legacy.name=Legacy Chest

tile.crops.wheat.name=Wheat Crops
tile.crops.wheat.desc=Wheat, plucked from the ground.
tile.crops.pumpkin.name=Pumpkin Crops
tile.crops.pumpkin.desc=A ripening pumpkin, plucked from the ground.

tile.farmland.dirt.name=Farmland
tile.farmland.dirt.desc=Tilled soil for growing crops.

tile.sign.post.planks.oak.name=Oak Signpost
tile.sign.post.planks.oak.desc=A free-standing oak sign.
tile.sign.wall.planks.oak.name=Oak Wall Sign
tile.sign.wall.planks.oak.desc=An oak sign placed on a wall.

tile.layer.snow.name=Snow Layer
tile.layer.snow.desc=A flat layer of snow.
tile.layer.leaves.oak.name=Leaf Pile
tile.layer.leaves.oak.desc=A pile of leaves.
tile.layer.slate.name=Slate Layer
tile.layer.slate.desc=A flat sheet of slate.

tile.ice.name=Ice
tile.ice.desc=Slippery frozen water.
tile.ice.perma.name=Perma-Ice
tile.ice.perma.desc=Ice imbued with the essence of stone.

tile.block.snow.name=Block of Snow
tile.block.snow.desc=Lots of snow compacted into a block.

tile.cactus.name=Cactus
tile.cactus.desc=A spiky plant that grows in the desert.

tile.block.clay.name=Block of Clay
tile.block.clay.desc=A block of compacted clay.

tile.sugarcane.name=Sugarcane
tile.sugarcane.desc=Not as sweet as you.

tile.block.sugarcane.name=Block of Sugarcane
tile.block.sugarcane.desc=One very big sugar cube.
tile.block.sugarcane.baked.name=Baked Block of Sugarcane
tile.block.sugarcane.baked.desc=Smells absolutely delicious.

tile.jukebox.name=Jukebox
tile.jukebox.desc=Plays your favourite tunes, assuming you have the right record.

tile.pumpkin.name=Pumpkin
tile.pumpkin.desc=An orange squash that grows in the wild.
tile.pumpkin.carved.idle.name=Carved Pumpkin
tile.pumpkin.carved.idle.desc=An orange squash with a spooky face.
tile.pumpkin.carved.active.name=Jack 'o' Lantern
tile.pumpkin.carved.active.desc=An orange squash with a spooky face, lit by a torch.

tile.netherrack.name=Netherrack
tile.netherrack.desc=Dark red rock that burns forever.
tile.netherrack.igneous.name=Igneous Netherrack
tile.netherrack.igneous.desc=Extreme heat has made this rock glow from inside.

tile.soulsand.name=Soul Sand
tile.soulsand.desc=Squishy brown sand that's tough to walk through.

tile.glowstone.name=Block of Glowstone
tile.glowstone.desc=Constantly emits a strong yellowish light.

tile.portal.nether.name=Nether Portal
tile.portal.nether.desc=A portal to the Nether.
tile.portal.paradise.name=Paradise Portal
tile.portal.paradise.desc=A portal to Paradise.

tile.cake.name=Cake
tile.cake.desc=I just can't cake it any more.
tile.cake.name=Pumpkin Pie
tile.cake.desc=I just can't pumpkin it any more.

tile.lamp.idle.name=Lamp
tile.lamp.idle.desc=How did you get this?!
tile.lamp.idle.black.name=Black Lamp
tile.lamp.idle.black.desc=A redstone lamp that can emit light. Tinted black.
tile.lamp.idle.red.name=Red Lamp
tile.lamp.idle.red.desc=A redstone lamp that can emit light. Tinted red.
tile.lamp.idle.green.name=Green Lamp
tile.lamp.idle.green.desc=A redstone lamp that can emit light. Tinted green.
tile.lamp.idle.brown.name=Brown Lamp
tile.lamp.idle.brown.desc=A redstone lamp that can emit light. Tinted brown.
tile.lamp.idle.blue.name=Blue Lamp
tile.lamp.idle.blue.desc=A redstone lamp that can emit light. Tinted blue.
tile.lamp.idle.purple.name=Purple Lamp
tile.lamp.idle.purple.desc=A redstone lamp that can emit light. Tinted purple.
tile.lamp.idle.cyan.name=Cyan Lamp
tile.lamp.idle.cyan.desc=A redstone lamp that can emit light. Tinted cyan.
tile.lamp.idle.silver.name=Light Gray Lamp
tile.lamp.idle.silver.desc=A redstone lamp that can emit light. Tinted light gray.
tile.lamp.idle.gray.name=Gray Lamp
tile.lamp.idle.gray.desc=A redstone lamp that can emit light. Tinted gray.
tile.lamp.idle.pink.name=Pink Lamp
tile.lamp.idle.pink.desc=A redstone lamp that can emit light. Tinted pink.
tile.lamp.idle.lime.name=Lime Lamp
tile.lamp.idle.lime.desc=A redstone lamp that can emit light. Tinted lime.
tile.lamp.idle.yellow.name=Yellow Lamp
tile.lamp.idle.yellow.desc=A redstone lamp that can emit light. Tinted yellow.
tile.lamp.idle.lightblue.name=Light Blue Lamp
tile.lamp.idle.lightblue.desc=A redstone lamp that can emit light. Tinted light blue.
tile.lamp.idle.magenta.name=Magenta Lamp
tile.lamp.idle.magenta.desc=A redstone lamp that can emit light. Tinted magenta.
tile.lamp.idle.orange.name=Orange Lamp
tile.lamp.idle.orange.desc=A redstone lamp that can emit light. Tinted orange.
tile.lamp.idle.white.name=White Lamp
tile.lamp.idle.white.desc=A redstone lamp that can emit light.

tile.lamp.active.name=Lit Lamp
tile.lamp.active.desc=How did you get this?!
tile.lamp.active.black.name=Lit Black Lamp
tile.lamp.active.black.desc=A redstone lamp that emits light. Tinted black.
tile.lamp.active.red.name=Lit Red Lamp
tile.lamp.active.red.desc=A redstone lamp that emits light. Tinted red.
tile.lamp.active.green.name=Lit Green Lamp
tile.lamp.active.green.desc=A redstone lamp that emits light. Tinted green.
tile.lamp.active.brown.name=Lit Brown Lamp
tile.lamp.active.brown.desc=A redstone lamp that emits light. Tinted brown.
tile.lamp.active.blue.name=Lit Blue Lamp
tile.lamp.active.blue.desc=A redstone lamp that emits light. Tinted blue.
tile.lamp.active.purple.name=Lit Purple Lamp
tile.lamp.active.purple.desc=A redstone lamp that emits light. Tinted purple.
tile.lamp.active.cyan.name=Lit Cyan Lamp
tile.lamp.active.cyan.desc=A redstone lamp that emits light. Tinted cyan.
tile.lamp.active.silver.name=Lit Light Gray Lamp
tile.lamp.active.silver.desc=A redstone lamp that emits light. Tinted light gray.
tile.lamp.active.gray.name=Lit Gray Lamp
tile.lamp.active.gray.desc=A redstone lamp that emits light. Tinted gray.
tile.lamp.active.pink.name=Lit Pink Lamp
tile.lamp.active.pink.desc=A redstone lamp that emits light. Tinted pink.
tile.lamp.active.lime.name=Lit Lime Lamp
tile.lamp.active.lime.desc=A redstone lamp that emits light. Tinted lime.
tile.lamp.active.yellow.name=Yellow Lamp
tile.lamp.active.yellow.desc=A redstone lamp that emits light. Tinted yellow.
tile.lamp.active.lightblue.name=Light Blue Lamp
tile.lamp.active.lightblue.desc=A redstone lamp that emits light. Tinted light blue.
tile.lamp.active.magenta.name=Magenta Lamp
tile.lamp.active.magenta.desc=A redstone lamp that emits light. Tinted magenta.
tile.lamp.active.orange.name=Orange Lamp
tile.lamp.active.orange.desc=A redstone lamp that emits light. Tinted orange.
tile.lamp.active.white.name=White Lamp
tile.lamp.active.white.desc=A redstone lamp that emits light.

tile.stone.polished.name=Polished Stone
tile.stone.polished.desc=A polished block of stone.
tile.granite.polished.name=Polished Granite
tile.granite.polished.desc=A polished block of granite.
tile.limestone.polished.name=Polished Limestone
tile.limestone.polished.desc=A polished block of limestone.
tile.basalt.polished.name=Polished Basalt
tile.basalt.polished.desc=A polished block of basalt.
tile.slate.polished.name=Polished Slate
tile.slate.polished.desc=A polished block of slate.

tile.candle.wax.soul.name=Soul Wax Candle
tile.candle.wax.soul.desc=A waxy brown candle that glows with an unnatural light.

tile.basket.name=Basket
tile.basket.desc=A wicker container for holding items.

tile.overlay.pebbles.name=Pebbles
tile.overlay.pebbles.desc=A cluster of pebbles.

tile.fence.chainlink.name=Chainlink Fence
tile.fence.chainlink.desc=A fence made of interconnected chain links. Can be climbed!
tile.fence.paper_wall.name=Paper Wall Fence
tile.fence.paper_wall.desc=A fence made of delicate paper. Be careful!

tile.lantern.firefly.green.name=Green Firefly Lantern
tile.lantern.firefly.green.desc=A glass jar containing a swarm of green fireflies.
tile.lantern.firefly.orange.name=Orange Firefly Lantern
tile.lantern.firefly.orange.desc=A glass jar containing a swarm of orange fireflies.
tile.lantern.firefly.blue.name=Blue Firefly Lantern
tile.lantern.firefly.blue.desc=A glass jar containing a swarm of blue fireflies.
tile.lantern.firefly.red.name=Red Firefly Lantern
tile.lantern.firefly.red.desc=A glass jar containing a swarm of red fireflies.

tile.flag.name=Flag
tile.flag.desc=A flag to mark your territory.

tile.paper_wall.name=Paper Wall
tile.paper_wall.desc=A wall made of delicate paper. Be careful!

tile.trapdoor.planks.oak.painted.name=Painted Trapdoor
tile.trapdoor.planks.oak.painted.desc=How did you get this?!
tile.trapdoor.planks.oak.painted.black.name=Black Oak Trapdoor
tile.trapdoor.planks.oak.painted.black.desc=Like a door, but flat and painted black.
tile.trapdoor.planks.oak.painted.red.name=Red Oak Trapdoor
tile.trapdoor.planks.oak.painted.red.desc=Like a door, but flat and painted red.
tile.trapdoor.planks.oak.painted.green.name=Green Oak Trapdoor
tile.trapdoor.planks.oak.painted.green.desc=Like a door, but flat and painted green.
tile.trapdoor.planks.oak.painted.brown.name=Brown Oak Trapdoor
tile.trapdoor.planks.oak.painted.brown.desc=Like a door, but flat and painted brown.
tile.trapdoor.planks.oak.painted.blue.name=Blue Oak Trapdoor
tile.trapdoor.planks.oak.painted.blue.desc=Like a door, but flat and painted blue.
tile.trapdoor.planks.oak.painted.purple.name=Purple Oak Trapdoor
tile.trapdoor.planks.oak.painted.purple.desc=Like a door, but flat and painted purple.
tile.trapdoor.planks.oak.painted.cyan.name=Cyan Oak Trapdoor
tile.trapdoor.planks.oak.painted.cyan.desc=Like a door, but flat and painted cyan.
tile.trapdoor.planks.oak.painted.silver.name=Light Gray Oak Trapdoor
tile.trapdoor.planks.oak.painted.silver.desc=Like a door, but flat and painted light gray.
tile.trapdoor.planks.oak.painted.gray.name=Gray Oak Trapdoor
tile.trapdoor.planks.oak.painted.gray.desc=Like a door, but flat and painted gray.
tile.trapdoor.planks.oak.painted.pink.name=Pink Oak Trapdoor
tile.trapdoor.planks.oak.painted.pink.desc=Like a door, but flat and painted pink.
tile.trapdoor.planks.oak.painted.lime.name=Lime Oak Trapdoor
tile.trapdoor.planks.oak.painted.lime.desc=Like a door, but flat and painted lime.
tile.trapdoor.planks.oak.painted.yellow.name=Yellow Oak Trapdoor
tile.trapdoor.planks.oak.painted.yellow.desc=Like a door, but flat and painted yellow.
tile.trapdoor.planks.oak.painted.lightblue.name=Light Blue Oak Trapdoor
tile.trapdoor.planks.oak.painted.lightblue.desc=Like a door, but flat and painted light blue.
tile.trapdoor.planks.oak.painted.magenta.name=Magenta Oak Trapdoor
tile.trapdoor.planks.oak.painted.magenta.desc=Like a door, but flat and painted magenta.
tile.trapdoor.planks.oak.painted.orange.name=Orange Oak Trapdoor
tile.trapdoor.planks.oak.painted.orange.desc=Like a door, but flat and painted orange.
tile.trapdoor.planks.oak.painted.white.name=White Oak Trapdoor
tile.trapdoor.planks.oak.painted.white.desc=Like a door, but flat and painted white.

tile.door.planks.oak.painted.bottom.name=Bottom Painted Wooden Door
tile.door.planks.oak.painted.bottom.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.black.name=Black Bottom Wooden Door
tile.door.planks.oak.painted.bottom.black.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.red.name=Red Bottom Wooden Door
tile.door.planks.oak.painted.bottom.red.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.green.name=Green Bottom Wooden Door
tile.door.planks.oak.painted.bottom.green.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.brown.name=Brown Bottom Wooden Door
tile.door.planks.oak.painted.bottom.brown.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.blue.name=Blue Bottom Wooden Door
tile.door.planks.oak.painted.bottom.blue.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.purple.name=Purple Bottom Wooden Door
tile.door.planks.oak.painted.bottom.purple.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.cyan.name=Cyan Bottom Wooden Door
tile.door.planks.oak.painted.bottom.cyan.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.silver.name=Light Gray Bottom Wooden Door
tile.door.planks.oak.painted.bottom.silver.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.gray.name=Gray Bottom Wooden Door
tile.door.planks.oak.painted.bottom.gray.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.pink.name=Pink Bottom Wooden Door
tile.door.planks.oak.painted.bottom.pink.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.lime.name=Lime Bottom Wooden Door
tile.door.planks.oak.painted.bottom.lime.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.yellow.name=Yellow Bottom Wooden Door
tile.door.planks.oak.painted.bottom.yellow.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.lightblue.name=Light Blue Bottom Wooden Door
tile.door.planks.oak.painted.bottom.lightblue.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.magenta.name=Magenta Bottom Wooden Door
tile.door.planks.oak.painted.bottom.magenta.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.orange.name=Orange Bottom Wooden Door
tile.door.planks.oak.painted.bottom.orange.desc=How did you get this?!
tile.door.planks.oak.painted.bottom.white.name=White Bottom Wooden Door
tile.door.planks.oak.painted.bottom.white.desc=How did you get this?!

tile.door.planks.oak.painted.top.name=Top Painted Wooden Door
tile.door.planks.oak.painted.top.desc=How did you get this?!
tile.door.planks.oak.painted.top.black.name=Black Top Wooden Door
tile.door.planks.oak.painted.top.black.desc=How did you get this?!
tile.door.planks.oak.painted.top.red.name=Red Top Wooden Door
tile.door.planks.oak.painted.top.red.desc=How did you get this?!
tile.door.planks.oak.painted.top.green.name=Green Top Wooden Door
tile.door.planks.oak.painted.top.green.desc=How did you get this?!
tile.door.planks.oak.painted.top.brown.name=Brown Top Wooden Door
tile.door.planks.oak.painted.top.brown.desc=How did you get this?!
tile.door.planks.oak.painted.top.blue.name=Blue Top Wooden Door
tile.door.planks.oak.painted.top.blue.desc=How did you get this?!
tile.door.planks.oak.painted.top.purple.name=Purple Top Wooden Door
tile.door.planks.oak.painted.top.purple.desc=How did you get this?!
tile.door.planks.oak.painted.top.cyan.name=Cyan Top Wooden Door
tile.door.planks.oak.painted.top.cyan.desc=How did you get this?!
tile.door.planks.oak.painted.top.silver.name=Light Gray Top Wooden Door
tile.door.planks.oak.painted.top.silver.desc=How did you get this?!
tile.door.planks.oak.painted.top.gray.name=Gray Top Wooden Door
tile.door.planks.oak.painted.top.gray.desc=How did you get this?!
tile.door.planks.oak.painted.top.pink.name=Pink Top Wooden Door
tile.door.planks.oak.painted.top.pink.desc=How did you get this?!
tile.door.planks.oak.painted.top.lime.name=Lime Top Wooden Door
tile.door.planks.oak.painted.top.lime.desc=How did you get this?!
tile.door.planks.oak.painted.top.yellow.name=Yellow Top Wooden Door
tile.door.planks.oak.painted.top.yellow.desc=How did you get this?!
tile.door.planks.oak.painted.top.lightblue.name=Light Blue Top Wooden Door
tile.door.planks.oak.painted.top.lightblue.desc=How did you get this?!
tile.door.planks.oak.painted.top.magenta.name=Magenta Top Wooden Door
tile.door.planks.oak.painted.top.magenta.desc=How did you get this?!
tile.door.planks.oak.painted.top.orange.name=Orange Top Wooden Door
tile.door.planks.oak.painted.top.orange.desc=How did you get this?!
tile.door.planks.oak.painted.top.white.name=White Top Wooden Door
tile.door.planks.oak.painted.top.white.desc=How did you get this?!

tile.door.glass.top.name=Glass Top Door
tile.door.glass.top.desc=You shouldn't be seeing this.
tile.door.glass.bottom.name=Glass Bottom Door
tile.door.glass.bottom.desc=And that's not just because it's glass.

tile.rope.name=Rope
tile.rope.desc=Rope, rope, rope your boat.
\ No newline at end of file
diff --git a/src/common/resources/recipes/workbench.json b/src/common/resources/recipes/workbench.json
index 6e2dd25c2..9d7a6afc5 100644
--- a/src/common/resources/recipes/workbench.json
+++ b/src/common/resources/recipes/workbench.json
@@ -7121,6 +7121,56 @@
     },
     "consumeContainers": false
   },
+
+  {
+    "name": "minecraft:workbench/pumpkin_pie",
+    "type": "minecraft:crafting/shaped",
+    "pattern": [
+      "AAA",
+      "BEB",
+      "CCC"
+    ],
+    "symbols": [
+      {
+        "symbol": "A",
+        "stack": {
+          "id": 16463,
+          "amount": 1,
+          "meta": 0
+        }
+      },
+      {
+        "symbol": "B",
+        "stack": {
+          "id": 16481,
+          "amount": 1,
+          "meta": 0
+        }
+      },
+      {
+        "symbol": "E",
+        "stack": {
+          "key": "tile.pumpkin",
+          "amount": 1,
+          "meta": 0
+        }
+      },
+      {
+        "symbol": "C",
+        "stack": {
+          "id": 16424,
+          "amount": 1,
+          "meta": 0
+        }
+      }
+    ],
+    "result": {
+      "key": "item.food.pumpkin_pie",
+      "amount": 1,
+      "meta": 0
+    },
+    "consumeContainers": false
+  },
   {
     "name": "minecraft:workbench/arrow",
     "type": "minecraft:crafting/shaped",
diff --git a/src/main/java/net/minecraft/client/Minecraft.java b/src/main/java/net/minecraft/client/Minecraft.java
index 858e62a38..d32b21f04 100644
--- a/src/main/java/net/minecraft/client/Minecraft.java
+++ b/src/main/java/net/minecraft/client/Minecraft.java
@@ -8,10 +8,11 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Random;
 
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
 import net.minecraft.client.render.item.model.ItemModelDispatcher;
-import net.minecraft.client.render.tessalator.TessellatorStandard;
 import net.minecraft.client.render.stitcher.TextureRegistry;
+import net.minecraft.client.render.tessalator.TessellatorStandard;
 import org.lwjgl.LWJGLException;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.input.Mouse;
@@ -65,6 +66,7 @@ import net.minecraft.client.render.EffectRenderer;
 import net.minecraft.client.render.EntityRenderDispatcher;
 import net.minecraft.client.render.FontRenderer;
 import net.minecraft.client.render.ItemRenderer;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.LoadingScreenRenderer;
 import net.minecraft.client.render.OpenGLHelper;
 import net.minecraft.client.render.PostProcessingManager;
@@ -147,11 +149,12 @@ public class Minecraft
 {
     public static final String VERSION = Global.VERSION;
     public static final boolean isMultiplayerDisabled = false;
+    public static boolean doPartialTick = true;
     private static Minecraft INSTANCE;
     public PlayerController playerController;
     public boolean hasCrashed;
     public UnexpectedThrowable lastCrash;
-    private Timer timer;
+    private final Timer timer;
     public World theWorld;
     public RenderGlobal renderGlobal;
     public EntityPlayerSP thePlayer;
@@ -772,7 +775,7 @@ public class Minecraft
                     Vec3d.initializePool();
                     
                     if(Display.isCloseRequested()) shutdown();
-                    if(isGamePaused && theWorld != null)
+                    if(isGamePaused && theWorld != null && !(currentScreen instanceof GuiModelViewer))
                     {
                         float temp = timer.partialTicks;
                         timer.advanceTime();
@@ -781,6 +784,7 @@ public class Minecraft
                     {
                         timer.advanceTime();
                     }
+                    if (!doPartialTick) timer.partialTicks = 1f;
                     long nanoTime = System.nanoTime();
 
                     mouseInput.update();
@@ -1360,7 +1364,9 @@ public class Minecraft
                                     if (profile != null && profile.isOperator)
                                     {
                                         fullbright = !fullbright;
-                                        renderGlobal.loadRenderers();
+                                        if(!LightmapHelper.isLightmapEnabled()) {
+                                        	renderGlobal.loadRenderers();	
+                                        }
                                     }
                                 }
                                 else
@@ -1368,7 +1374,9 @@ public class Minecraft
                                     if (theWorld.getLevelData().getCheatsEnabled())
                                     {
                                         fullbright = !fullbright;
-                                        renderGlobal.loadRenderers();
+                                        if(!LightmapHelper.isLightmapEnabled()) {
+                                        	renderGlobal.loadRenderers();	
+                                        }
                                     }
                                 }
                                 ingameGUI.guiHeldItemTooltip.setString("Fullbright: " + (fullbright ? "On" : "Off"));
diff --git a/src/main/java/net/minecraft/client/entity/fx/EntityBubbleFX.java b/src/main/java/net/minecraft/client/entity/fx/EntityBubbleFX.java
index d64ca9cdc..acd4bc5c7 100644
--- a/src/main/java/net/minecraft/client/entity/fx/EntityBubbleFX.java
+++ b/src/main/java/net/minecraft/client/entity/fx/EntityBubbleFX.java
@@ -10,11 +10,13 @@ import net.minecraft.core.world.World;
 
 public class EntityBubbleFX extends EntityFX
 {
+    private final boolean needsWater;
 
     public EntityBubbleFX(World world, double d, double d1, double d2,
-                          double d3, double d4, double d5)
+                          double d3, double d4, double d5, boolean needsWater)
     {
         super(world, d, d1, d2, d3, d4, d5);
+        this.needsWater = needsWater;
         particleRed = 1.0F;
         particleGreen = 1.0F;
         particleBlue = 1.0F;
@@ -38,7 +40,7 @@ public class EntityBubbleFX extends EntityFX
         xd *= 0.85D;
         yd *= 0.85D;
         zd *= 0.85D;
-        if(world.getBlockMaterial(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z)) != Material.water)
+        if(needsWater && world.getBlockMaterial(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z)) != Material.water)
         {
             remove();
         }
diff --git a/src/main/java/net/minecraft/client/entity/fx/EntityDiggingFX.java b/src/main/java/net/minecraft/client/entity/fx/EntityDiggingFX.java
index 900235783..e88af6d34 100644
--- a/src/main/java/net/minecraft/client/entity/fx/EntityDiggingFX.java
+++ b/src/main/java/net/minecraft/client/entity/fx/EntityDiggingFX.java
@@ -20,7 +20,7 @@ public class EntityDiggingFX extends EntityFX
         this.side = Side.getSideById(i);
         this.block = block;
         particleTexture = BlockModelDispatcher.getInstance().getDispatch(block).getParticleTexture(side, meta);
-        this.particleGravity = block.blockParticleGravity;
+        this.particleGravity = block != null ? block.blockParticleGravity : 0;
         this.particleRed = particleGreen = particleBlue = 0.6F;
         this.particleScale /= 2.0F;
 
diff --git a/src/main/java/net/minecraft/client/entity/fx/EntityFX.java b/src/main/java/net/minecraft/client/entity/fx/EntityFX.java
index 024e9ff7d..a2a923c92 100644
--- a/src/main/java/net/minecraft/client/entity/fx/EntityFX.java
+++ b/src/main/java/net/minecraft/client/entity/fx/EntityFX.java
@@ -23,6 +23,9 @@ public class EntityFX extends Entity
         setSize(0.2F, 0.2F);
         heightOffset = bbHeight / 2.0F;
         setPos(x, y, z);
+        xo = this.x;
+        yo = this.y;
+        zo = this.z;
         particleRed = particleGreen = particleBlue = 1.0F;
         this.xd = motionX + (double)((float)(java.lang.Math.random() * 2D - 1.0D) * 0.4F);
         this.yd = motionY + (double)((float)(java.lang.Math.random() * 2D - 1.0D) * 0.4F);
diff --git a/src/main/java/net/minecraft/client/gui/GuiButton.java b/src/main/java/net/minecraft/client/gui/GuiButton.java
index bc1eb8450..2c910ffbe 100644
--- a/src/main/java/net/minecraft/client/gui/GuiButton.java
+++ b/src/main/java/net/minecraft/client/gui/GuiButton.java
@@ -20,6 +20,7 @@ public class GuiButton extends Gui implements GuiElement
     public int id;
     public boolean enabled;
     public boolean visible;
+    public boolean playSound = true;
     public Listener<GuiButton> listener;
 
     public GuiButton(int id, int xPosition, int yPosition, String text)
diff --git a/src/main/java/net/minecraft/client/gui/GuiInventoryCreative.java b/src/main/java/net/minecraft/client/gui/GuiInventoryCreative.java
index 949d03579..780b5760c 100644
--- a/src/main/java/net/minecraft/client/gui/GuiInventoryCreative.java
+++ b/src/main/java/net/minecraft/client/gui/GuiInventoryCreative.java
@@ -30,7 +30,7 @@ public class GuiInventoryCreative extends GuiInventory implements ITextChangeLis
 		xSize = 298;
 		container = (ContainerPlayerCreative)entityplayer.inventorySlots;
 		armourValuesFloat = 186;
-		armourButtonFloatX = 76;
+		armourButtonFloatX = 81;
 		overlayButtonsLayout.setOffset(-(xSize / 2), -(ySize / 2) - 10);
 	}
 	
diff --git a/src/main/java/net/minecraft/client/gui/GuiMainMenu.java b/src/main/java/net/minecraft/client/gui/GuiMainMenu.java
index 4c9022154..554d88199 100644
--- a/src/main/java/net/minecraft/client/gui/GuiMainMenu.java
+++ b/src/main/java/net/minecraft/client/gui/GuiMainMenu.java
@@ -16,8 +16,8 @@ import java.util.Random;
 import javax.imageio.ImageIO;
 
 import net.minecraft.client.render.block.model.BlockModelDispatcher;
-import net.minecraft.client.render.tessalator.TessellatorStandard;
 import net.minecraft.client.render.stitcher.TextureRegistry;
+import net.minecraft.client.render.tessalator.TessellatorStandard;
 import net.minecraft.core.Global;
 import org.lwjgl.input.Keyboard;
 import org.lwjgl.opengl.GL11;
@@ -169,6 +169,9 @@ public class GuiMainMenu extends GuiScreen
         controlList.add(new GuiClickableLabel(6, d, height - 24 - d, i18n.translateKey("gui.main_menu.button.minecraft_forum"), 0x63A121));
         controlList.add(new GuiClickableLabel(7, d, height - 12 - d, i18n.translateKey("gui.main_menu.button.youtube"), 0xFF0000));
         controlList.add(new GuiTexturedButton(8, "/gui/gui.png", width / 2 + 104, i + 72 + 12, 0, 86, 20, 20));
+        GuiButton debugButton = new GuiButton(9, width - 8, height - 8, 8, 8, "");
+        debugButton.visible = false;
+        controlList.add(debugButton);
         if(mc.session == null)
         {
             multiplayerButton.enabled = false;
@@ -207,6 +210,9 @@ public class GuiMainMenu extends GuiScreen
         {
             mc.displayGuiScreen(new GuiOptions(this, OptionsPages.LANGUAGE));
         }
+        if(button.id == 9){
+            mc.displayGuiScreen(new GuiOptions(this, OptionsPages.DEBUG));
+        }
         Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
         if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE))
         {
diff --git a/src/main/java/net/minecraft/client/gui/GuiPaintingPicker.java b/src/main/java/net/minecraft/client/gui/GuiPaintingPicker.java
index 3b963bea7..6a2a46539 100644
--- a/src/main/java/net/minecraft/client/gui/GuiPaintingPicker.java
+++ b/src/main/java/net/minecraft/client/gui/GuiPaintingPicker.java
@@ -88,26 +88,26 @@ public class GuiPaintingPicker
 
         artEntries.clear();
 
-        artEntries.add(new ArtEntry(centerArt, centerX - offsetX, centerY - (centerArt.sizeY / 2) * scale, 1.0f));
+        artEntries.add(new ArtEntry(centerArt, centerX - offsetX, centerY - ((centerArt.sizeY  * scale) / 2), 1.0f));
 
         ArtType currentArt = ArtType.getNext(centerArt);
 
-        int dy = (centerArt.sizeY / 2 + artGap) * scale + 22;
+        int dy = ((centerArt.sizeY * scale) / 2 + artGap) + 28;
         while (currentArt != centerArt)
         {
             int pCenterY = dy;
             float alpha = 1 - (float) pCenterY / (height / 2f);
 
             artEntries.add(new ArtEntry(currentArt, centerX - offsetX, centerY + dy, alpha * 0.75f));
-            dy += (currentArt.sizeY + artGap) * scale;
+            dy += ((currentArt.sizeY * scale) + artGap);
             currentArt = ArtType.getNext(currentArt);
         }
 
         currentArt = ArtType.getPrevious(centerArt);
-        dy = -(centerArt.sizeY / 2) * scale;
+        dy = -((centerArt.sizeY  * scale) / 2);
         while (currentArt != centerArt)
         {
-            dy -= (currentArt.sizeY + artGap) * scale;
+            dy -= ((currentArt.sizeY  * scale) + artGap);
             int pCenterY = dy + currentArt.sizeY * scale;
             float alpha = 1 - (float) -pCenterY / (height / 2f);
 
@@ -136,13 +136,17 @@ public class GuiPaintingPicker
         {
             if (entry.alpha > 0)
             {
+                GL11.glColor4f(1f, 1f, 1f, 1f);
                 if (mouseX > entry.x && mouseX < entry.x + entry.art.sizeX * scale && mouseY > entry.y && mouseY < entry.y + entry.art.sizeY * scale)
                 {
                     GL11.glDisable(GL11.GL_TEXTURE_2D);
                     drawRectWidthHeight(entry.x - scale, entry.y - scale, (entry.art.sizeX + 2) * scale, (entry.art.sizeY + 2) * scale, 0xFFFFFFFF);
                     GL11.glEnable(GL11.GL_TEXTURE_2D);
+                    drawPainting(entry.art, entry.x, entry.y, entry.art.sizeX, entry.art.sizeY, 1f);
+                } else {
+                    drawPainting(entry.art, entry.x, entry.y, entry.art.sizeX, entry.art.sizeY, entry.alpha);
                 }
-                drawPainting(entry.art, entry.x, entry.y, entry.art.sizeX, entry.art.sizeY, entry.alpha);
+
             }
         }
 
@@ -160,7 +164,7 @@ public class GuiPaintingPicker
     {
         coordinate.parentAtlas.bindTexture();
         TessellatorStandard tessellator = TessellatorStandard.instance;
-        tessellator.setColorRGBA_F(1f, 1f, 1f, alpha);
+        GL11.glColor4f(1f, 1f, 1f, alpha);
         tessellator.startDrawingQuads();
         tessellator.addVertexWithUV(x + 0,      y + height, zLevel, coordinate.getIconUMin(), coordinate.getIconVMax());
         tessellator.addVertexWithUV(x + width,  y + height, zLevel, coordinate.getIconUMax(), coordinate.getIconVMax());
diff --git a/src/main/java/net/minecraft/client/gui/GuiPhotoMode.java b/src/main/java/net/minecraft/client/gui/GuiPhotoMode.java
index 3835b0282..aa7c17200 100644
--- a/src/main/java/net/minecraft/client/gui/GuiPhotoMode.java
+++ b/src/main/java/net/minecraft/client/gui/GuiPhotoMode.java
@@ -38,24 +38,24 @@ public class GuiPhotoMode extends GuiScreen
 
     public boolean showPlayer = true;
 
-    private float iRotation = 0;
-    private float lastIRotation = 0;
-    private float iRotationGoal = 0;
-    private float iZoom = 1;
-    private float lastIZoom = 1;
-    private float iZoomGoal = 1;
-    private float iTilt = 30;
-    private float lastITilt = 30;
-    private float iTiltGoal = 30;
+    protected float iRotation = 0;
+    protected float lastIRotation = 0;
+    protected float iRotationGoal = 0;
+    protected float iZoom = 1;
+    protected float lastIZoom = 1;
+    protected float iZoomGoal = 1;
+    protected float iTilt = 30;
+    protected float lastITilt = 30;
+    protected float iTiltGoal = 30;
     private float iFog = 1;
     private float lastIFog = 1;
     private float iFogGoal = 1;
-    private float iPanX = 0;
-    private float lastIPanX = 0;
-    private float iPanXGoal = 0;
-    private float iPanY = 0;
-    private float lastIPanY = 0;
-    private float iPanYGoal = 0;
+    protected float iPanX = 0;
+    protected float lastIPanX = 0;
+    protected float iPanXGoal = 0;
+    protected float iPanY = 0;
+    protected float lastIPanY = 0;
+    protected float iPanYGoal = 0;
 
     private boolean isMouseDown = false;
     private int mouseButton;
@@ -67,13 +67,13 @@ public class GuiPhotoMode extends GuiScreen
 
     public float intensityValue = 1.0f;
 
-    boolean shouldScreenshot = false;
+    protected boolean shouldScreenshot = false;
     
-    private PhotoModeRenderer photoModeRenderer;
+    protected PhotoModeRenderer photoModeRenderer;
     
     public Renderer previousRenderer;
     
-    private boolean showHelpText = true;
+    protected boolean showHelpText = true;
 
     public GuiPhotoMode()
     {
@@ -306,7 +306,7 @@ public class GuiPhotoMode extends GuiScreen
         }
     }
 
-    private long lastUpdateTime = 0;
+    protected long lastUpdateTime = 0;
     @Override
     public void drawScreen(int mouseX, int mouseY, float partialTick)
     {
diff --git a/src/main/java/net/minecraft/client/gui/GuiScreen.java b/src/main/java/net/minecraft/client/gui/GuiScreen.java
index e35388b83..0643984d7 100644
--- a/src/main/java/net/minecraft/client/gui/GuiScreen.java
+++ b/src/main/java/net/minecraft/client/gui/GuiScreen.java
@@ -73,7 +73,7 @@ public class GuiScreen extends Gui
         if(mouseButton == 0)
         {
             for (GuiButton guiButton : controlList) {
-                if (guiButton.mouseClicked(mc, mouseX, mouseY)) {
+                if (guiButton.mouseClicked(mc, mouseX, mouseY) && guiButton.playSound) {
                     selectedButton = guiButton;
                     mc.sndManager.playSound("random.click", SoundCategory.GUI_SOUNDS, 1.0F, 1.0F);
                     if (guiButton.listener != null) {
diff --git a/src/main/java/net/minecraft/client/gui/GuiTextField.java b/src/main/java/net/minecraft/client/gui/GuiTextField.java
index f9be61b70..140320b76 100644
--- a/src/main/java/net/minecraft/client/gui/GuiTextField.java
+++ b/src/main/java/net/minecraft/client/gui/GuiTextField.java
@@ -5,7 +5,6 @@ import net.minecraft.client.render.FontRenderer;
 import org.lwjgl.input.Keyboard;
 
 import net.minecraft.client.gui.text.ITextField;
-import org.lwjgl.opengl.GL11;
 
 public class GuiTextField extends Gui implements ITextField
 {
@@ -163,7 +162,7 @@ public class GuiTextField extends Gui implements ITextField
     public void setTextChangeListener(ITextChangeListener textChangeListener) {
 		this.textChangeListener = textChangeListener;
 	}
-    
+
     public interface ITextChangeListener
     {
     	void textChanged(GuiTextField textField);
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/GuiModelViewer.java b/src/main/java/net/minecraft/client/gui/modelviewer/GuiModelViewer.java
new file mode 100644
index 000000000..1f154d214
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/GuiModelViewer.java
@@ -0,0 +1,482 @@
+package net.minecraft.client.gui.modelviewer;
+
+import com.b100.utils.ImageUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiPhotoMode;
+import net.minecraft.client.gui.modelviewer.categories.BlockCategory;
+import net.minecraft.client.gui.modelviewer.categories.EntityCategory;
+import net.minecraft.client.gui.modelviewer.categories.ModelViewerCategory;
+import net.minecraft.client.gui.modelviewer.categories.ParticleCategory;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerButton;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerSlider;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerTextField;
+import net.minecraft.client.gui.modelviewer.elements.IListenerElement;
+import net.minecraft.client.gui.options.GuiOptions;
+import net.minecraft.client.gui.options.data.OptionsPages;
+import net.minecraft.client.render.Texture;
+import net.minecraft.client.render.TileEntityRenderDispatcher;
+import net.minecraft.client.render.shader.PhotoModeRenderer;
+import net.minecraft.client.render.shader.Shaders;
+import net.minecraft.client.render.shader.ShadersRenderer;
+import net.minecraft.client.render.tessalator.TessellatorStandard;
+import net.minecraft.client.util.helper.Textures;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.item.Item;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.helper.Buffer;
+import net.minecraft.core.world.World;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import static org.lwjgl.opengl.GL11.GL_RGBA;
+import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
+import static org.lwjgl.opengl.GL11.GL_TEXTURE_HEIGHT;
+import static org.lwjgl.opengl.GL11.GL_TEXTURE_WIDTH;
+import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE;
+import static org.lwjgl.opengl.GL11.glGetError;
+import static org.lwjgl.opengl.GL11.glGetTexImage;
+import static org.lwjgl.opengl.GL11.glGetTexLevelParameteri;
+
+public class GuiModelViewer extends GuiPhotoMode implements GuiListenerTextField.ITextChangeListener {
+    private GuiListenerButton buttonRotateLeft;
+    private GuiListenerButton buttonRotateRight;
+    private GuiListenerButton buttonCenterScreen;
+    private GuiListenerButton buttonTakeScreenshot;
+    private GuiListenerButton buttonExit;
+    private GuiListenerSlider sliderTilt;
+    private GuiListenerButton buttonShaders;
+    private GuiListenerSlider sliderIntensity;
+    public GuiListenerButton buttonPrevEntry;
+    public GuiListenerButton buttonNextEntry;
+    private GuiListenerButton buttonCategory;
+    private GuiListenerButton buttonReloadTextures;
+    private GuiListenerButton buttonTickToggle;
+    private final ModelViewerCategory entityCategory = new EntityCategory(this);
+    private final ModelViewerCategory particleCategory = new ParticleCategory(this);
+    private final ModelViewerCategory blockCategory = new BlockCategory(this);
+    public final List<ModelViewerCategory> categories = new ArrayList<>();
+    private ModelViewerCategory currentCategory;
+    protected final int defaultRed = (int) (255 * 0.25f);
+    protected final int defaultGreen = (int) (255 * 0.25f);
+    protected final int defaultBlue = (int) (255 * 0.35f);
+    protected int bgRed = defaultRed;
+    protected int bgGreen = defaultGreen;
+    protected int bgBlue = defaultBlue;
+
+    protected boolean tickProgress = true;
+    protected boolean rotateToCamera = true;
+    public GuiModelViewer(){
+        this.mc = Minecraft.getMinecraft(this);
+        mc.thePlayer.absMoveTo(0.5, 64.5, 0.5, 180, 0);
+        mc.thePlayer.noPhysics = true;
+        mc.renderEngine.refreshTexturesAndDisplayErrors();
+        mc.renderEngine.updateDynamicTextures();
+
+        if(Shaders.enableShaders) {
+            photoModeRenderer = new PhotoModeRenderer(mc, this);
+        }
+
+        this.previousRenderer = mc.render;
+        showPlayer = false;
+        showHelpText = false;
+        lastIZoom = iZoom = iZoomGoal = 8.5f;
+
+        mc.ppm.reset();
+
+        iRotationGoal = iRotation = -2;
+
+        categories.add(blockCategory);
+        categories.add(entityCategory);
+        categories.add(particleCategory);
+        setCategory(entityCategory);
+    }
+    @Override
+    public void init()
+    {
+        controlList.clear();
+        I18n i18n = I18n.getInstance();
+
+        List<GuiButton> leftSideButtons = new ArrayList<>();
+
+        buttonExit = new GuiListenerButton(5, 0, height - 20, 20, 20, "X");
+        buttonExit.setActionListener(this::exitToMenu);
+
+        buttonRotateLeft = new GuiListenerButton(0, width / 2 - 49 - 2 - 20, height - 20, 20, 20, "<");
+        buttonRotateLeft.setActionListener(() -> {
+            iRotationGoal += 1;
+            iRotationGoal = (int) iRotationGoal;
+        });
+        buttonRotateRight = new GuiListenerButton(1, width / 2 + 49 + 2, height - 20, 20, 20, ">");
+        buttonRotateRight.setActionListener(() -> {
+            iRotationGoal -= 1;
+            iRotationGoal = (int) iRotationGoal;
+        });
+        buttonTakeScreenshot = new GuiListenerButton(4, width / 2 - 49, height - 20, 98, 20, i18n.translateKey("gui.photo_mode.button.take_screenshot"));
+        buttonTakeScreenshot.setActionListener(this::screenShot);
+
+        buttonPrevEntry = new GuiListenerButton(10, width / 2 - 49 - 2 - 20, height - 40 - 2, 20, 20, "<");
+        buttonPrevEntry.setActionListener(() -> currentCategory.cycleCategoryEntry(-1));
+        buttonNextEntry = new GuiListenerButton(11, width / 2 + 49 + 2, height - 40 - 2, 20, 20, ">");
+        buttonNextEntry.setActionListener(() -> currentCategory.cycleCategoryEntry(1));
+        buttonCategory = new GuiListenerButton(12, width / 2 - 49, height - 40 - 2, 98, 20, i18n.translateKey(currentCategory.getCategoryNameKey()));
+        buttonCategory.setActionListener(() -> setCategory(categories.get((categories.indexOf(currentCategory) + 1) % categories.size())));
+        buttonCategory.setOnValueChanged(() -> buttonCategory.displayString = i18n.translateKey(currentCategory.getCategoryNameKey()));
+
+        buttonReloadTextures = new GuiListenerButton(12, 21, height - 20, 98, 20, i18n.translateKey("gui.model_viewer.button.reload_textures"));
+        buttonReloadTextures.setActionListener(() -> mc.renderEngine.refreshTexturesAndDisplayErrors());
+
+        buttonCenterScreen = new GuiListenerButton(10, 0, 0, 120, 20, i18n.translateKey("gui.photo_mode.button.center_camera"));
+        buttonCenterScreen.setActionListener(() -> {
+            iPanXGoal = 0;
+            iPanYGoal = 0;
+        });
+
+        buttonTickToggle = new GuiListenerButton(13, width - 120, 0, 99, 20, i18n.translateKeyAndFormat("gui.model_viewer.button.tickprogress", tickProgress));
+        buttonTickToggle.setActionListener(() -> tickProgress = !tickProgress);
+        buttonTickToggle.setOnValueChanged(() -> buttonTickToggle.displayString = i18n.translateKeyAndFormat("gui.model_viewer.button.tickprogress", tickProgress));
+
+        GuiListenerButton cameraRotateButton = new GuiListenerButton(-1, width - 120, 0, 120, 20, i18n.translateKeyAndFormat("gui.model_viewer.button.rotate", rotateToCamera));
+        cameraRotateButton.setActionListener(() -> {
+            rotateToCamera = !rotateToCamera;
+            cameraRotateButton.displayString = i18n.translateKeyAndFormat("gui.model_viewer.button.rotate", rotateToCamera);
+        });
+
+        GuiListenerButton buttonManualTick = new GuiListenerButton(14, width - 21, 0, 20, 20, "+");
+        buttonManualTick.setActionListener(this::entryTick);
+
+        sliderTilt = new GuiListenerSlider(7, 0, 0, 120, 20, i18n.translateKey("gui.photo_mode.button.tilt.default"), iTiltGoal / 90f);
+        sliderTilt.setOnValueChanged(() ->{
+            // Update tilt slider
+            String tilt = i18n.translateKey("gui.photo_mode.button.tilt.default");
+            if ((int)(sliderTilt.sliderValue * 90.0f) != 30)
+            {
+                tilt = (int)(sliderTilt.sliderValue * 90.0f) + " degrees";
+            }
+            sliderTilt.displayString = i18n.translateKeyAndFormat("gui.photo_mode.button.tilt", tilt);
+            if (sliderTilt.dragging)
+            {
+                iTiltGoal = (float) (int)(sliderTilt.sliderValue * 90.0f);
+            }
+        });
+        if(Shaders.enableShaders) {
+            buttonShaders = new GuiListenerButton(8, 0, 0, 120, 20, i18n.translateKeyAndFormat("gui.photo_mode.button.shader", i18n.translateKey("gui.photo_mode.button.shader.none")));
+            buttonShaders.setActionListener(() -> {
+                boolean ctrl = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL);
+                if (ctrl)
+                {
+                    photoModeRenderer.first();
+                }
+                else
+                {
+                    photoModeRenderer.next();
+                }
+                sliderIntensity.enabled = photoModeRenderer.getActiveShader() != null;
+            });
+            buttonShaders.setOnValueChanged(() -> {
+                String activeShader = photoModeRenderer.getActiveShader();
+                if (activeShader == null) activeShader = i18n.translateKey("gui.photo_mode.button.shader.none");
+                activeShader = activeShader.toUpperCase(Locale.ROOT);
+                buttonShaders.displayString = i18n.translateKeyAndFormat("gui.photo_mode.button.shader", activeShader);
+            });
+            sliderIntensity = new GuiListenerSlider(9, 0, 0, 120, 20, i18n.translateKeyAndFormat("gui.photo_mode.button.intensity", (int)(intensityValue * 100) + "%"), intensityValue);
+            sliderIntensity.setOnValueChanged(() ->{
+                // Update intensity slider
+                sliderIntensity.displayString = i18n.translateKeyAndFormat("gui.photo_mode.button.intensity", (int)(sliderIntensity.sliderValue * 100) + "%");
+                if (sliderIntensity.dragging) {
+                    intensityValue = sliderIntensity.sliderValue;
+                }
+            });
+
+            if (photoModeRenderer.getActiveShader() == null) {
+                sliderIntensity.enabled = false;
+            }
+        }
+
+        if(Shaders.enableShaders) {
+            mc.setRenderer(photoModeRenderer);
+        }
+
+        controlList.add(cameraRotateButton);
+        controlList.add(buttonTickToggle);
+
+        int i=0;
+        List<GuiButton> _buttons = new ArrayList<>(controlList);
+        for(GuiButton button : _buttons) {
+            button.yPosition = i++ * 21;
+        }
+
+        controlList.add(buttonManualTick);
+        buttonManualTick.yPosition = buttonTickToggle.yPosition;
+
+        currentCategory.addContextButtons(controlList);
+
+        leftSideButtons.add(buttonCenterScreen);
+        leftSideButtons.add(sliderTilt);
+
+        if(Shaders.enableShaders) {
+            leftSideButtons.add(buttonShaders);
+            leftSideButtons.add(sliderIntensity);
+        }
+
+        int j = 0;
+        for (GuiButton button: leftSideButtons){
+            button.yPosition = j++ * 21;
+        }
+
+        controlList.addAll(leftSideButtons);
+
+        GuiListenerTextField rField = new GuiListenerTextField(this, fontRenderer, 0, j++ * 21, 40, 20, String.valueOf(bgRed), "Red");
+        rField.setPrefaceText("R: ");
+        rField.setKeyListener(key -> {
+            try {
+                bgRed = Integer.parseInt(rField.getText());
+            } catch (Exception ignored){}
+        });
+        rField.setActionListener(() -> {
+            if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)){
+                rField.setText(String.valueOf(defaultRed));
+                bgRed = defaultRed;
+            }
+        });
+        GuiListenerTextField gField = new GuiListenerTextField(this, fontRenderer, 40, rField.yPosition, 40, 20, String.valueOf(bgGreen), "Green");
+        gField.setPrefaceText("G: ");
+        gField.setKeyListener(key -> {
+            try {
+                bgGreen = Integer.parseInt(gField.getText());
+            } catch (Exception ignored){}
+        });
+        gField.setActionListener(() -> {
+            if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)){
+                gField.setText(String.valueOf(defaultGreen));
+                bgGreen = defaultGreen;
+            }
+        });
+        GuiListenerTextField bField = new GuiListenerTextField(this, fontRenderer, 80, rField.yPosition, 40, 20, String.valueOf(bgBlue), "Blue");
+        bField.setPrefaceText("B: ");
+        bField.setKeyListener(key -> {
+            try {
+                bgBlue = Integer.parseInt(bField.getText());
+            } catch (Exception ignored){}
+        });
+        bField.setActionListener(() -> {
+            if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)){
+                bField.setText(String.valueOf(defaultBlue));
+                bgBlue = defaultBlue;
+            }
+        });
+
+        controlList.add(rField);
+        controlList.add(gField);
+        controlList.add(bField);
+
+        controlList.add(buttonRotateLeft);
+        controlList.add(buttonRotateRight);
+        controlList.add(buttonTakeScreenshot);
+        controlList.add(buttonPrevEntry);
+        controlList.add(buttonNextEntry);
+        controlList.add(buttonCategory);
+        controlList.add(buttonReloadTextures);
+        controlList.add(buttonExit);
+    }
+    private void setCategory(ModelViewerCategory category){
+        if (currentCategory != null){
+            currentCategory.onClose();
+        }
+        currentCategory = category;
+        if (currentCategory != null){
+            currentCategory.onOpen();
+        }
+        init();
+    }
+    public static int cycleItemId(int itemId, int offset){
+        int id = (itemId + Item.itemsList.length + offset) % Item.itemsList.length;
+        while (Item.itemsList[id] == null){
+            id = (id + (int) Math.signum(offset) + Item.itemsList.length) % Item.itemsList.length;
+        }
+        return id;
+    }
+    @Override
+    public void drawScreen(int mouseX, int mouseY, float partialTick)
+    {
+        GL11.glViewport(0, 0, mc.resolution.width, mc.resolution.height);
+        GL11.glMatrixMode(GL11.GL_PROJECTION);
+        GL11.glLoadIdentity();
+        GL11.glMatrixMode(GL11.GL_MODELVIEW /*GL_MODELVIEW0_ARB*/);
+        GL11.glLoadIdentity();
+        GL11.glClear(256);
+        GL11.glMatrixMode(GL11.GL_PROJECTION);
+        GL11.glLoadIdentity();
+        GL11.glOrtho(0.0D, mc.resolution.scaledWidth, mc.resolution.scaledHeight, 0.0D, 1000D, 3000D);
+        GL11.glMatrixMode(GL11.GL_MODELVIEW /*GL_MODELVIEW0_ARB*/);
+        GL11.glLoadIdentity();
+        GL11.glTranslatef(0.0F, 0.0F, -2000F);
+
+        if (rotateToCamera){
+            mc.thePlayer.yRotO = mc.thePlayer.yRot = getRotation(partialTick) * 45f - 135f;
+        } else {
+            mc.thePlayer.yRotO = mc.thePlayer.yRot = 180;
+        }
+
+        lastIZoom = iZoom;
+        if (iZoom != iZoomGoal)
+        {
+            iZoom += (iZoomGoal - iZoom) * 0.08f;
+            if (Math.abs(iZoom - iZoomGoal) < 0.0005f) iZoom = iZoomGoal;
+        }
+
+        lastIRotation = iRotation;
+        if (iRotation != iRotationGoal)
+        {
+            iRotation += (iRotationGoal - iRotation) * 0.08f;
+            if (Math.abs(iRotation - iRotationGoal) < 0.0005f) iRotation = iRotationGoal;
+        }
+
+        lastITilt = iTilt;
+        if (iTilt != iTiltGoal)
+        {
+            iTilt += (iTiltGoal - iTilt) * 0.08f;
+            if (Math.abs(iTilt - iTiltGoal) < 0.01f) iTilt = iTiltGoal;
+        }
+
+        lastIPanX = iPanX;
+        if (iPanX != iPanXGoal)
+        {
+            iPanX += (iPanXGoal - iPanX) * 0.4f;
+            if (Math.abs(iPanX - iPanXGoal) < 0.01f) iPanX = iPanXGoal;
+        }
+
+        lastIPanY = iPanY;
+        if (iPanY != iPanYGoal)
+        {
+            iPanY += (iPanYGoal - iPanY) * 0.4f;
+            if (Math.abs(iPanY - iPanYGoal) < 0.01f) iPanY = iPanYGoal;
+        }
+
+        buttonCenterScreen.enabled = (iPanX != 0 || iPanY != 0) && !(iPanXGoal == 0 && iPanYGoal == 0);
+
+        List<GuiButton> _buttons = new ArrayList<>(controlList);
+        for (GuiButton guibutton : _buttons) {
+            guibutton.drawButton(mc, mouseX, mouseY);
+        }
+
+        scroll(Mouse.getDWheel());
+
+        TileEntityRenderDispatcher.instance.renderTileEntity(TessellatorStandard.instance, new TileEntity(), -0.5D, -0.75D, -0.5D, partialTick);
+
+        drawStringCentered(fontRenderer, currentCategory.getCurrentDisplayInfo(I18n.getInstance()), width/2, 1, 0xffffff);
+    }
+    @Override
+    public void keyTyped(char c, int key, int mouseX, int mouseY)
+    {
+        if (key == Keyboard.KEY_ESCAPE) {
+            exitToMenu();
+        }
+        List<GuiButton> _buttons = new ArrayList<>(controlList);
+        for (GuiButton button : _buttons){
+            if (button instanceof IListenerElement && button.isHovered(mouseX, mouseY)){
+                ((IListenerElement) button).onKeyTyped(c, key);
+            }
+        }
+    }
+    private void exitToMenu(){
+        currentCategory.onClose();
+        mc.changeWorld(null);
+        mc.displayGuiScreen(new GuiOptions(null, OptionsPages.DEBUG));
+    }
+    public static int cycleBlockId(int id, int idOff){
+        int id2 = (id + Block.blocksList.length + idOff) % Block.blocksList.length;
+        while (Block.blocksList[id2] == null){
+            id2 = (id2 + (int) Math.signum(idOff) + Block.blocksList.length) % Block.blocksList.length;
+        }
+        return id2;
+    }
+    @Override
+    public void onClosed() {
+        if(Shaders.enableShaders) {
+            mc.setRenderer(previousRenderer);
+        }
+        Minecraft.doPartialTick = true;
+    }
+    @Override
+    public void tick()
+    {
+        super.tick();
+        List<GuiButton> _buttons = new ArrayList<>(controlList);
+        for (GuiButton button : _buttons){
+            if (button instanceof GuiListenerButton){
+                ((GuiListenerButton) button).tick();
+            }
+        }
+        if (tickProgress){
+            entryTick();
+        }
+        Minecraft.doPartialTick = tickProgress;
+    }
+    private void entryTick(){
+        mc.renderEngine.updateDynamicTextures();
+        mc.effectRenderer.updateEffects();
+        currentCategory.onTick();
+        // TODO this fixes world time based animation, but also ticks things like wind and im not certain on the best way to set wind direction arbitrarily right now
+//        mc.theWorld.getLevelData().setWorldTime(mc.theWorld.getWorldTime() + 1);
+    }
+    @Override
+    protected void buttonPressed(GuiButton button) {
+        // Overrides the regular GuiPhotomode's method
+    }
+
+    public long timeLastKeyPressed = System.currentTimeMillis();
+    @Override
+    public void textChanged(GuiListenerTextField textField) {
+        timeLastKeyPressed = System.currentTimeMillis();
+    }
+    public float[] getBackgroundFogColor(){
+        return new float[]{bgRed/255f, bgGreen/255f, bgBlue/255f};
+    }
+    private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
+    public void screenShot(){
+        try {
+            File screenshotsDir = new File(mc.getMinecraftDir(), "screenshots");
+            screenshotsDir.mkdir();
+            Texture texture = ((ShadersRenderer)mc.render).getWorldFramebufferTex();
+            texture.bind();
+
+            int w = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH);
+            int h = glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT);
+
+            int size = w * h * 4;
+            Buffer.checkBufferSize(size);
+            ByteBuffer buffer = Buffer.buffer;
+
+            buffer.position(0).limit(size);
+            glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+            if(glGetError() == 0) {
+                buffer.position(0);
+                File outPut;
+                String timeStamp = "Render_" + dateFormat.format(new Date());
+                int id = 1;
+                while ((outPut = new File(screenshotsDir, timeStamp + (id != 1 ? "_" + id : "") + ".png")).exists()) {
+                    id++;
+                }
+                ImageUtils.saveExternalImage(Textures.getImage(buffer, w, h, true, true), outPut);
+
+            }else {
+                System.out.println("Cannot get pixel data");
+            }
+        } catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/BlockCategory.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/BlockCategory.java
new file mode 100644
index 000000000..d699db98a
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/BlockCategory.java
@@ -0,0 +1,203 @@
+package net.minecraft.client.gui.modelviewer.categories;
+
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import net.minecraft.client.gui.modelviewer.categories.entries.block.BasicBlockEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.block.BlockEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.block.JarEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.block.MobSpawnerEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.block.SignEntry;
+import net.minecraft.client.gui.modelviewer.elements.GuiTextCycle;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.entity.EntityItem;
+import net.minecraft.core.enums.EnumDropCause;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.chunk.DisplayChunk;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class BlockCategory extends ModelViewerCategory {
+    public List<GuiButton> buttonBuffer = new ArrayList<>();
+    public HashMap<Block, BlockEntry> entryHashMap = new HashMap<>();
+    public GuiTextCycle<Integer> blockIdTextField;
+    public GuiTextCycle<Integer> blockMetaTextField;
+    public BlockCategory(GuiModelViewer modelViewer) {
+        super(modelViewer);
+        createEntries();
+    }
+    public void createEntries(){
+        for (Block block : Block.blocksList){
+            if (block == null) continue;
+            entryHashMap.put(block, new BasicBlockEntry(block));
+        }
+        entryHashMap.put(Block.signWallPlanksOak, new SignEntry(Block.signWallPlanksOak));
+        entryHashMap.put(Block.signPostPlanksOak, new SignEntry(Block.signPostPlanksOak));
+        entryHashMap.put(Block.mobspawner, new MobSpawnerEntry());
+        entryHashMap.put(Block.jarGlass, new JarEntry());
+    }
+
+    @Override
+    public String getCategoryNameKey() {
+        return "model.category.block.name";
+    }
+
+    @Override
+    public String getCurrentDisplayInfo(I18n translator) {
+        Block displayBlock = Block.getBlock(DisplayChunk.displayBlockId);
+        String name = "None";
+        if (displayBlock != null){
+            name = I18n.getInstance().translateNameKey(displayBlock.getKey());
+            ItemStack[] nameStack = displayBlock.getBreakResult(mc.theWorld, EnumDropCause.PICK_BLOCK, DisplayChunk.displayBlockPosX, DisplayChunk.displayBlockPosY, DisplayChunk.displayBlockPosZ, DisplayChunk.displayBlockMeta, DisplayChunk.displayTileEntity);
+            if (nameStack != null && nameStack.length > 0){
+                name = nameStack[0].getDisplayName();
+            }
+        }
+        return translator.translateKeyAndFormat("model.category.block.info", name);
+    }
+
+    @Override
+    public void addContextButtons(List<GuiButton> buttonList) {
+        GuiButton lastButton = buttonList.get(buttonList.size()-1);
+        buttonBuffer.clear();
+
+        modelViewer.buttonNextEntry.enabled = false;
+        modelViewer.buttonPrevEntry.enabled = false;
+
+        boolean wasFocused = false;
+        if (blockIdTextField != null){
+            wasFocused = blockIdTextField.textField.isFocused;
+        }
+        blockIdTextField = new GuiTextCycle<Integer>(modelViewer, mc.fontRenderer, modelViewer.width - 120, lastButton.yPosition + 21, 120, 20, DisplayChunk.displayBlockId) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return GuiModelViewer.cycleBlockId(current, offset);
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = MathHelper.clamp(Integer.parseInt(s), 0, Block.blocksList.length);
+                    if (Block.getBlock(id) != null){
+                        return id;
+                    }
+                } catch (Exception ignored){}
+                return DisplayChunk.displayBlockId;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        blockIdTextField.textField.setFocused(wasFocused);
+        blockIdTextField.textField.setPrefaceText("ID: ");
+        blockIdTextField.textField.setPlaceholder("Block ID");
+        blockIdTextField.setOnValueChanged(() -> setDisplayBlock(blockIdTextField.getCurrentElement(), 0));
+
+        buttonList.add(blockIdTextField);
+
+        wasFocused = false;
+        if (blockMetaTextField != null){
+            wasFocused = blockMetaTextField.textField.isFocused;
+        }
+        blockMetaTextField = new GuiTextCycle<Integer>(modelViewer, mc.fontRenderer, modelViewer.width - 120, blockIdTextField.yPosition + 21, 120, 20, 0) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return (current + offset) & 0xFF;
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int meta = Integer.parseInt(s);
+                    return MathHelper.clamp(meta, 0, 255);
+                } catch (Exception ignored){}
+                return DisplayChunk.displayBlockMeta;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        blockMetaTextField.textField.setFocused(wasFocused);
+        blockMetaTextField.textField.setPlaceholder("Meta");
+        blockMetaTextField.textField.setPrefaceText("Meta: ");
+        blockMetaTextField.setOnValueChanged(() -> setDisplayBlock(DisplayChunk.displayBlockId, blockMetaTextField.getCurrentElement()));
+        buttonList.add(blockMetaTextField);
+
+        int yPos = blockMetaTextField.yPosition + 21;
+        int xPos = modelViewer.width;
+
+        BlockEntry entry = entryHashMap.get(Block.getBlock(DisplayChunk.displayBlockId));
+
+        if (entry != null){
+            List<GuiButton> list = entry.getEntryButtons(mc, modelViewer, mc.theWorld, DisplayChunk.displayBlockMeta);
+            if (list != null){
+                for (GuiButton button : list) {
+                    button.setX(button.getX() + xPos);
+                    button.setY(button.getY() + yPos);
+                }
+                buttonList.addAll(list);
+            }
+        }
+    }
+
+    @Override
+    public void cycleCategoryEntry(int offset) {
+
+    }
+
+    @Override
+    public void onOpen() {
+        setDisplayBlock(1, 0);
+    }
+
+    @Override
+    public void onClose() {
+        setDisplayBlock(0, 0);
+    }
+
+    @Override
+    public void onTick() {
+        BlockEntry entry = entryHashMap.get(Block.getBlock(DisplayChunk.displayBlockId));
+        if (entry != null){
+            entry.onTick(mc.theWorld, DisplayChunk.displayBlockMeta);
+        }
+        // Delete any items blocks create when added/removed
+        mc.theWorld.loadedEntityList.removeIf(entity -> entity instanceof EntityItem);
+    }
+    public void setDisplayBlock(int id, int meta){
+        Block displayBlock = Block.blocksList[DisplayChunk.displayBlockId];
+        BlockEntry entry = entryHashMap.get(Block.getBlock(DisplayChunk.displayBlockId));
+        int _id = DisplayChunk.displayBlockId;
+        int _meta = DisplayChunk.displayBlockMeta;
+
+        if (displayBlock != null && _id != id){
+            displayBlock.onBlockRemoved(mc.theWorld, (int) mc.thePlayer.x, (int) mc.thePlayer.y, (int) mc.thePlayer.z, _meta);
+        }
+        if (entry != null){
+            entry.onClose(mc.theWorld, DisplayChunk.displayBlockMeta);
+        }
+        DisplayChunk.displayBlockPosX = (int) mc.thePlayer.x;
+        DisplayChunk.displayBlockPosY = (int) mc.thePlayer.y;
+        DisplayChunk.displayBlockPosZ = (int) mc.thePlayer.z;
+        DisplayChunk.displayBlockId = id;
+        DisplayChunk.displayBlockMeta = meta;
+        displayBlock = Block.blocksList[id];
+        if (displayBlock != null && _id != id){
+            entry = entryHashMap.get(Block.getBlock(DisplayChunk.displayBlockId));
+            displayBlock.onBlockAdded(mc.theWorld, (int) mc.thePlayer.x, (int) mc.thePlayer.y, (int) mc.thePlayer.z);
+            if (entry != null) entry.onOpen(mc.theWorld, DisplayChunk.displayBlockMeta);
+        }
+        if (_id != id){
+            modelViewer.init();
+        }
+        mc.effectRenderer.clearEffects(mc.theWorld);
+        mc.renderGlobal.loadRenderers();
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/EntityCategory.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/EntityCategory.java
new file mode 100644
index 000000000..ef8f5e3a6
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/EntityCategory.java
@@ -0,0 +1,203 @@
+package net.minecraft.client.gui.modelviewer.categories;
+
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.DispatcherEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityArmoredZombieEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityBoatEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityCreeperEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityFallingSandEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityFireflyEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityItemEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityMinecartEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityPaintingEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntitySheepEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntitySlimeEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityTNTEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.entity.EntityWolfEntry;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerTextField;
+import net.minecraft.client.gui.modelviewer.elements.GuiTextCycle;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.EntityDispatcher;
+import net.minecraft.core.entity.EntityLiving;
+import net.minecraft.core.entity.monster.EntityHuman;
+import net.minecraft.core.entity.monster.EntityZombie;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.helper.MathHelper;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class EntityCategory extends ModelViewerCategory{
+    public HashMap<Class<? extends Entity>, EntityEntry<?>> entryMap = new HashMap<>();
+    public List<EntityEntry<?>> entryList = new ArrayList<>();
+    public GuiListenerTextField entityName;
+    public GuiTextCycle<Integer> entityVariant;
+    public EntityEntry<?> currentEntry = EntityEntry.blankEntry;
+    public Entity displayEntity;
+    public EntityCategory(GuiModelViewer modelViewer) {
+        super(modelViewer);
+        createEntries();
+    }
+    public void createEntries(){
+        for (String s : EntityDispatcher.classToKeyMap.values()){
+            try{
+                addEntry(new DispatcherEntry(s));
+            } catch (Exception ignore){}
+        }
+        addEntry(new EntityItemEntry());
+        addEntry(new EntityFireflyEntry());
+        addEntry(new EntitySheepEntry());
+        addEntry(new EntityWolfEntry());
+        addEntry(new EntityCreeperEntry());
+        addEntry(new EntityArmoredZombieEntry());
+        addEntry(new EntitySlimeEntry());
+        addEntry(new EntityMinecartEntry());
+        addEntry(new EntityBoatEntry());
+        addEntry(new EntityFallingSandEntry());
+        addEntry(new EntityTNTEntry());
+        addEntry(new EntityPaintingEntry());
+    }
+    public void addEntry(EntityEntry<?> entry){
+        Entity entity = entry.getEntityInstance(mc, mc.theWorld);
+        if (entity == null) return;
+        EntityEntry<?> oldEntry = entryMap.put(entity.getClass(), entry);
+        entryList.remove(oldEntry);
+        entryList.add(entry);
+    }
+    @SuppressWarnings("unchecked")
+    public <V extends Entity> EntityEntry<V> getEntry(V entity){
+        return (EntityEntry<V>) entryMap.getOrDefault(entity.getClass(), EntityEntry.blankEntry);
+    }
+
+    @Override
+    public String getCategoryNameKey() {
+        return "model.category.entity.name";
+    }
+
+    @Override
+    public String getCurrentDisplayInfo(I18n translator) {
+        String title = "None";
+        if (displayEntity != null){
+            title = Entity.getNameFromEntity(displayEntity, false);
+        }
+        return translator.translateKeyAndFormat("model.category.entity.info", title);
+    }
+
+    @Override
+    public void addContextButtons(List<GuiButton> buttonList) {
+        GuiButton lastButton = buttonList.get(buttonList.size()-1);
+        boolean isLiving = displayEntity instanceof EntityLiving;
+        if (isLiving){
+            entityVariant = new GuiTextCycle<Integer>(modelViewer, mc.fontRenderer, modelViewer.width - 120, lastButton.yPosition + 21, 120, 20, 0) {
+                @Override
+                public Integer cycleElement(Integer current, int offset) {
+                    return (current + offset) & 0x7F;
+                }
+
+                @Override
+                public Integer getElementFromString(String s) {
+                    try {
+                        int id = Integer.parseInt(s);
+                        return MathHelper.clamp(id, 0, Byte.MAX_VALUE);
+                    } catch (Exception ignored){}
+                    return (int) displayEntity.getEntityData().getByte(1);
+                }
+
+                @Override
+                public String getNameFromElement(Integer element) {
+                    return String.valueOf(element);
+                }
+            };
+            entityVariant.setOnValueChanged(() -> ((EntityLiving) displayEntity).setSkinVariant(entityVariant.getCurrentElement()));
+            entityVariant.textField.setPlaceholder("Variant");
+            entityVariant.textField.setPrefaceText("Variant: ");
+            buttonList.add(entityVariant);
+
+            entityName = new GuiListenerTextField(modelViewer, mc.fontRenderer, modelViewer.width - 120, entityVariant.yPosition + 21, 120, 20, "", "Nickname");
+            entityName.setTextChangeListener(modelViewer);
+            buttonList.add(entityName);
+        }
+
+        lastButton = buttonList.get(buttonList.size()-1);
+        int xPos = modelViewer.width;
+        int yPos = lastButton.getY() + lastButton.getHeight() + 1;
+
+        List<GuiButton> entryButtons = getEntry(displayEntity).getEntryButtons(mc, modelViewer, displayEntity);
+        if (entryButtons != null){
+            for (GuiButton button : entryButtons) {
+                button.setX(button.getX() + xPos);
+                button.setY(button.getY() + yPos);
+            }
+            buttonList.addAll(entryButtons);
+        }
+    }
+
+    @Override
+    public void cycleCategoryEntry(int offset) {
+        int id = 0;
+        List<EntityEntry<?>> _val = new ArrayList<>(entryList);
+        if (currentEntry != EntityEntry.blankEntry){
+            id = _val.indexOf(currentEntry);
+        }
+        currentEntry.onClose();
+        currentEntry = _val.get((id + _val.size() + offset) % _val.size());
+        currentEntry.onOpen();
+
+        setDisplayEntity(currentEntry.getEntityInstance(mc, mc.theWorld));
+    }
+
+    @Override
+    public void onOpen() {
+        currentEntry = entryMap.get(EntityZombie.class);
+        currentEntry.onOpen();
+        setDisplayEntity(currentEntry.getEntityInstance(mc, mc.theWorld));
+    }
+
+    @Override
+    public void onClose() {
+        currentEntry.onClose();
+        removeDisplayEntity();
+    }
+
+    @Override
+    public void onTick(){
+        if (displayEntity != null){
+            displayEntity.tickCount++;
+            getEntry(displayEntity).onTick(displayEntity);
+        }
+        if (!(displayEntity instanceof EntityHuman) || System.currentTimeMillis() > modelViewer.timeLastKeyPressed + 1000){
+            if (displayEntity != null && displayEntity instanceof EntityLiving){
+                String oldNick = ((EntityLiving) displayEntity).nickname;
+                if (!oldNick.equals(entityName.getText())){
+                    ((EntityLiving) displayEntity).setNickname(entityName.getText());
+                }
+            }
+        }
+    }
+    public void setDisplayEntity(Entity entity){
+        removeDisplayEntity();
+        displayEntity = entity;
+        if (displayEntity != null){
+            displayEntity.noPhysics = true;
+
+            displayEntity.absMoveTo(mc.thePlayer.x, mc.thePlayer.y - displayEntity.bbHeight/2, mc.thePlayer.z, displayEntity.yRot, displayEntity.xRot);
+            displayEntity.lerpMotion(0, 0, 0);
+            mc.theWorld.entityJoinedWorld(displayEntity);
+            if (displayEntity instanceof EntityLiving){
+                ((EntityLiving) displayEntity).setSkinVariant(0);
+            }
+        }
+        mc.effectRenderer.clearEffects(mc.theWorld);
+        modelViewer.init();
+    }
+    public void removeDisplayEntity(){
+        if (displayEntity != null){
+            displayEntity.remove();
+            mc.theWorld.loadedEntityList.remove(displayEntity);
+        }
+        mc.effectRenderer.clearEffects(mc.theWorld);
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/ModelViewerCategory.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/ModelViewerCategory.java
new file mode 100644
index 000000000..821e75e33
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/ModelViewerCategory.java
@@ -0,0 +1,24 @@
+package net.minecraft.client.gui.modelviewer.categories;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import net.minecraft.core.lang.I18n;
+
+import java.util.List;
+
+public abstract class ModelViewerCategory {
+    protected final GuiModelViewer modelViewer;
+    protected final Minecraft mc;
+    public ModelViewerCategory(GuiModelViewer modelViewer){
+        this.modelViewer = modelViewer;
+        this.mc = Minecraft.getMinecraft(this);
+    }
+    public abstract String getCategoryNameKey();
+    public abstract String getCurrentDisplayInfo(I18n translator);
+    public abstract void addContextButtons(List<GuiButton> buttonList);
+    public abstract void cycleCategoryEntry(int offset);
+    public abstract void onOpen();
+    public abstract void onClose();
+    public abstract void onTick();
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/ParticleCategory.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/ParticleCategory.java
new file mode 100644
index 000000000..a015ecdc8
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/ParticleCategory.java
@@ -0,0 +1,132 @@
+package net.minecraft.client.gui.modelviewer.categories;
+
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import net.minecraft.client.gui.modelviewer.categories.entries.particle.BlockFXEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.particle.BubbleFXEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.particle.GenericFXEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.particle.ItemFXEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.particle.LeafFXEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.particle.NoteFXEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.particle.ParticleEntry;
+import net.minecraft.client.gui.modelviewer.categories.entries.particle.RedDustFXEntry;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerSlider;
+import net.minecraft.core.lang.I18n;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ParticleCategory extends ModelViewerCategory{
+    public List<ParticleEntry> entries = new ArrayList<>();
+    public double spawnRadius = 0;
+    public ParticleEntry currentEntry;
+
+    public ParticleCategory(GuiModelViewer modelViewer) {
+        super(modelViewer);
+        initEntries();
+    }
+    private void initEntries(){
+        entries.add(new BubbleFXEntry());
+        entries.add(new GenericFXEntry("smoke"));
+        entries.add(new NoteFXEntry());
+        entries.add(new GenericFXEntry("portal"));
+        entries.add(new GenericFXEntry("explode"));
+        entries.add(new GenericFXEntry("flame"));
+        entries.add(new GenericFXEntry("blueflame"));
+        entries.add(new GenericFXEntry("soulflame"));
+        entries.add(new GenericFXEntry("lava"));
+        entries.add(new GenericFXEntry("footstep"));
+        entries.add(new GenericFXEntry("splash"));
+        entries.add(new GenericFXEntry("largesmoke"));
+        entries.add(new RedDustFXEntry());
+        entries.add(new ItemFXEntry());
+        entries.add(new BlockFXEntry());
+        entries.add(new GenericFXEntry("snowshovel"));
+        entries.add(new GenericFXEntry("heart"));
+        entries.add(new GenericFXEntry("slimechunk"));
+        entries.add(new GenericFXEntry("fireflyGreen"));
+        entries.add(new GenericFXEntry("fireflyBlue"));
+        entries.add(new GenericFXEntry("fireflyOrange"));
+        entries.add(new GenericFXEntry("fireflyRed"));
+        entries.add(new GenericFXEntry("arrowtrail"));
+        entries.add(new LeafFXEntry());
+        entries.add(new GenericFXEntry("boatbreak"));
+    }
+    private void setCurrentEntry(ParticleEntry entry){
+        if (currentEntry != null){
+            currentEntry.onClose();
+        }
+        currentEntry = entry;
+        if (currentEntry != null){
+            currentEntry.onOpen();
+        }
+    }
+
+    @Override
+    public String getCategoryNameKey() {
+        return "model.category.particle.name";
+    }
+
+    @Override
+    public String getCurrentDisplayInfo(I18n translator) {
+        return translator.translateKeyAndFormat("model.category.particle.info", currentEntry.getParticleName(translator));
+    }
+
+    @Override
+    public void addContextButtons(List<GuiButton> buttonList) {
+        GuiButton lastButton = buttonList.get(buttonList.size()-1);
+        GuiListenerSlider radiusSlider = new GuiListenerSlider(-1, modelViewer.width - 120, lastButton.yPosition + 21, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.particle.radius.slider", ((int)(spawnRadius * 100))/100f), (float) spawnRadius);
+        radiusSlider.setOnValueChanged(() ->{
+            spawnRadius = radiusSlider.sliderValue;
+            radiusSlider.displayString = I18n.getInstance().translateKeyAndFormat("model.category.particle.radius.slider", ((int)(spawnRadius * 100))/100f);
+        });
+        buttonList.add(radiusSlider);
+
+        int xPos = modelViewer.width;
+        int yPos = radiusSlider.getY() + radiusSlider.getHeight() + 1;
+
+        List<GuiButton> buttons = currentEntry.getEntryButtons(mc, modelViewer);
+        if (buttons != null){
+            for (GuiButton button: buttons){
+                button.setX(button.getX() + xPos);
+                button.setY(button.getY() + yPos);
+            }
+            buttonList.addAll(buttons);
+        }
+    }
+
+    @Override
+    public void cycleCategoryEntry(int offset) {
+        setCurrentEntry(entries.get((entries.indexOf(currentEntry) + entries.size() + offset) % entries.size()));
+        mc.effectRenderer.clearEffects(mc.theWorld);
+        modelViewer.init();
+    }
+
+    @Override
+    public void onOpen() {
+        spawnRadius = 0;
+        setCurrentEntry(entries.get(0));
+    }
+
+    @Override
+    public void onClose() {
+        mc.effectRenderer.clearEffects(mc.theWorld);
+        currentEntry.onClose();
+    }
+
+    @Override
+    public void onTick() {
+        double offX = 0;
+        double offY = 0;
+        double offZ = 0;
+        if (spawnRadius > 0){
+            offX = mc.theWorld.rand.nextDouble() - mc.theWorld.rand.nextDouble();
+            offY = mc.theWorld.rand.nextDouble() - mc.theWorld.rand.nextDouble();
+            offZ = mc.theWorld.rand.nextDouble() - mc.theWorld.rand.nextDouble();
+        }
+        offX *= spawnRadius;
+        offY *= spawnRadius;
+        offZ *= spawnRadius;
+        currentEntry.spawnParticle(mc, mc.theWorld, mc.thePlayer.x + offX, mc.thePlayer.y + offY, mc.thePlayer.z + offZ);
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/BasicBlockEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/BasicBlockEntry.java
new file mode 100644
index 000000000..ec6d09414
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/BasicBlockEntry.java
@@ -0,0 +1,35 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.block;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.world.World;
+
+import java.util.List;
+
+public class BasicBlockEntry extends BlockEntry{
+    public BasicBlockEntry(Block block) {
+        super(block);
+    }
+
+    @Override
+    public void onTick(World world, int meta) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, World world, int meta) {
+        return null;
+    }
+
+    @Override
+    public void onClose(World world, int meta) {
+
+    }
+
+    @Override
+    public void onOpen(World world, int meta) {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/BlockEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/BlockEntry.java
new file mode 100644
index 000000000..5725909fc
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/BlockEntry.java
@@ -0,0 +1,21 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.block;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.world.World;
+
+import java.util.List;
+
+public abstract class BlockEntry {
+    public Block block;
+    public BlockEntry(Block block){
+        this.block = block;
+    }
+
+    public abstract void onTick(World world, int meta);
+    public abstract List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, World world, int meta);
+    public abstract void onClose(World world, int meta);
+    public abstract void onOpen(World world, int meta);
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/JarEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/JarEntry.java
new file mode 100644
index 000000000..7fa0c24ed
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/JarEntry.java
@@ -0,0 +1,67 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.block;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import net.minecraft.client.gui.modelviewer.elements.GuiTextCycle;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.TileEntityFlowerJar;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.DisplayChunk;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class JarEntry extends BlockEntry{
+    public JarEntry() {
+        super(Block.jarGlass);
+    }
+
+    @Override
+    public void onTick(World world, int meta) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, World world, int meta) {
+        GuiTextCycle<Integer> jarCycle = new GuiTextCycle<Integer>(parentScreen, mc.fontRenderer, - 120, 0, 120, 20, 0) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return GuiModelViewer.cycleBlockId(current, offset);
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = MathHelper.clamp(Integer.parseInt(s), 0, Block.blocksList.length);
+                    if (Block.getBlock(id) != null){
+                        return id;
+                    }
+                } catch (Exception ignored){}
+                return DisplayChunk.displayBlockId;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        jarCycle.textField.setPrefaceText("Jar: ");
+        jarCycle.textField.setPlaceholder("Jar ID");
+        jarCycle.setOnValueChanged(() -> ((TileEntityFlowerJar)DisplayChunk.displayTileEntity).flowerInPot = jarCycle.getCurrentElement());
+
+        return new ArrayList<GuiButton>(){{add(jarCycle);}};
+    }
+
+    @Override
+    public void onClose(World world, int meta) {
+
+    }
+
+    @Override
+    public void onOpen(World world, int meta) {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/MobSpawnerEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/MobSpawnerEntry.java
new file mode 100644
index 000000000..6a884f8e8
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/MobSpawnerEntry.java
@@ -0,0 +1,61 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.block;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListSelectorButton;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.TileEntityMobSpawner;
+import net.minecraft.core.entity.EntityDispatcher;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.DisplayChunk;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MobSpawnerEntry extends BlockEntry{
+    public MobSpawnerEntry() {
+        super(Block.mobspawner);
+    }
+
+    @Override
+    public void onTick(World world, int meta) {
+        TileEntityMobSpawner spawner = (TileEntityMobSpawner) DisplayChunk.displayTileEntity;
+        spawner.yaw2 = spawner.yaw;
+        double xPos = (double) spawner.x + spawner.worldObj.rand.nextFloat();
+        double yPos = (double) spawner.y + spawner.worldObj.rand.nextFloat();
+        double zPos = (double) spawner.z + spawner.worldObj.rand.nextFloat();
+        spawner.worldObj.spawnParticle("smoke", xPos, yPos, zPos, 0.0D, 0.0D, 0.0D);
+        spawner.worldObj.spawnParticle("flame", xPos, yPos, zPos, 0.0D, 0.0D, 0.0D);
+        for(spawner.yaw += 1000F / ((float)spawner.delay + 200F); spawner.yaw > 360D;)
+        {
+            spawner.yaw -= 360D;
+            spawner.yaw2 -= 360D;
+        }
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, World world, int meta) {
+        List<String> ids = new ArrayList<>(EntityDispatcher.keyToClassMap.keySet());
+        ids.remove("mob");
+        GuiListSelectorButton<String> dispatcherIds = new GuiListSelectorButton<String>(-1, -120, 0, 120, 20, I18n.getInstance().translateKey("model.category.block.spawner.button.id"), ids, "Pig") {
+            @Override
+            public String getNameFromElement(String element) {
+                return element;
+            }
+        };
+        dispatcherIds.setOnValueChanged(() -> ((TileEntityMobSpawner)DisplayChunk.displayTileEntity).setMobId(dispatcherIds.getCurrentElement()));
+        return new ArrayList<GuiButton>(){{add(dispatcherIds);}};
+    }
+
+    @Override
+    public void onClose(World world, int meta) {
+
+    }
+
+    @Override
+    public void onOpen(World world, int meta) {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/SignEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/SignEntry.java
new file mode 100644
index 000000000..af1fba73a
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/block/SignEntry.java
@@ -0,0 +1,54 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.block;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerTextField;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.TileEntitySign;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.DisplayChunk;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SignEntry extends BlockEntry{
+    public SignEntry(Block block) {
+        super(block);
+    }
+
+    @Override
+    public void onTick(World world, int meta) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, World world, int meta) {
+        TileEntitySign sign = (TileEntitySign)DisplayChunk.displayTileEntity;
+        GuiListenerTextField line1 = new GuiListenerTextField(parentScreen, mc.fontRenderer, -120, 0,                       120, 20, "", "Line 1");
+        GuiListenerTextField line2 = new GuiListenerTextField(parentScreen, mc.fontRenderer, -120, line1.yPosition + 21,    120, 20, "", "Line 2");
+        GuiListenerTextField line3 = new GuiListenerTextField(parentScreen, mc.fontRenderer, -120, line2.yPosition + 21,    120, 20, "", "Line 3");
+        GuiListenerTextField line4 = new GuiListenerTextField(parentScreen, mc.fontRenderer, -120, line3.yPosition + 21,    120, 20, "", "Line 4");
+        line1.setOnValueChanged(() -> sign.signText[0] = line1.getText());
+        line2.setOnValueChanged(() -> sign.signText[1] = line2.getText());
+        line3.setOnValueChanged(() -> sign.signText[2] = line3.getText());
+        line4.setOnValueChanged(() -> sign.signText[3] = line4.getText());
+        return new ArrayList<GuiButton>(){
+            {
+                add(line1);
+                add(line2);
+                add(line3);
+                add(line4);
+            }};
+    }
+
+    @Override
+    public void onClose(World world, int meta) {
+        DisplayChunk.setDisplayTileEntity(world, null);
+    }
+
+    @Override
+    public void onOpen(World world, int meta) {
+        DisplayChunk.setDisplayTileEntity(world, new TileEntitySign());
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/BlankEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/BlankEntry.java
new file mode 100644
index 000000000..9766af221
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/BlankEntry.java
@@ -0,0 +1,36 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.world.World;
+
+import java.util.List;
+
+public class BlankEntry extends EntityEntry<Entity> {
+    @Override
+    public void onTick(Entity entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, Entity entity) {
+        return null;
+    }
+
+    @Override
+    public Entity getEntityInstance(Minecraft mc, World world) {
+        return null;
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/DispatcherEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/DispatcherEntry.java
new file mode 100644
index 000000000..1551922d5
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/DispatcherEntry.java
@@ -0,0 +1,41 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.entity.EntityDispatcher;
+import net.minecraft.core.world.World;
+
+import java.util.List;
+
+public class DispatcherEntry extends EntityEntry<Entity> {
+    public final String id;
+    public DispatcherEntry(String dispatcherId){
+        id = dispatcherId;
+    }
+    @Override
+    public void onTick(Entity entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, Entity entity) {
+        return null;
+    }
+
+    @Override
+    public Entity getEntityInstance(Minecraft mc, World world) {
+        return EntityDispatcher.createEntityInWorld(id, Minecraft.getMinecraft(this).theWorld);
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityArmoredZombieEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityArmoredZombieEntry.java
new file mode 100644
index 000000000..b8339e7a1
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityArmoredZombieEntry.java
@@ -0,0 +1,49 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerButton;
+import net.minecraft.core.entity.monster.EntityArmoredZombie;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityArmoredZombieEntry extends EntityEntry<EntityArmoredZombie>{
+    @Override
+    public void onTick(EntityArmoredZombie entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityArmoredZombie armoredZombie) {
+        List<GuiButton> buttonList = new ArrayList<>();
+        GuiListenerButton swordButton = new GuiListenerButton(-1, - 120, 0, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.armored_zombie.button.sword", false));
+        swordButton.setActionListener(() -> {
+            boolean hasSword1 = armoredZombie.getHeldItem() != null;
+            armoredZombie.setHoldingSword(!hasSword1);
+            swordButton.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.armored_zombie.button.sword", hasSword1);
+        });
+        buttonList.add(swordButton);
+        return buttonList;
+    }
+
+    @Override
+    public EntityArmoredZombie getEntityInstance(Minecraft mc, World world) {
+        EntityArmoredZombie armoredZombie = new EntityArmoredZombie(world);
+        armoredZombie.setHoldingSword(false);
+        return armoredZombie;
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityBoatEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityBoatEntry.java
new file mode 100644
index 000000000..a9b502be5
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityBoatEntry.java
@@ -0,0 +1,55 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerButton;
+import net.minecraft.core.block.entity.TileEntityFlag;
+import net.minecraft.core.entity.vehicle.EntityBoat;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityBoatEntry extends EntityEntry<EntityBoat>{
+    @Override
+    public void onTick(EntityBoat entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityBoat entity) {
+        GuiListenerButton flagButton = new GuiListenerButton(-1, - 120, 0, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.boat.button.flag", false));
+        flagButton.setActionListener(() -> {
+            boolean flag;
+            if (entity.tileEntityFlag == null){
+                entity.tileEntityFlag = new TileEntityFlag();
+                flag = true;
+            } else {
+                entity.tileEntityFlag = null;
+                flag = false;
+            }
+            flagButton.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.boat.button.flag", flag);
+        });
+        return new ArrayList<GuiButton>(){{add(flagButton);}};
+    }
+
+    @Override
+    public EntityBoat getEntityInstance(Minecraft mc, World world) {
+        EntityBoat boat = new EntityBoat(world);
+        boat.yRot = 270f;
+        boat.zd = 100; // Causes the flag to rotate when enabled
+        return boat;
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityCreeperEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityCreeperEntry.java
new file mode 100644
index 000000000..2fe012e36
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityCreeperEntry.java
@@ -0,0 +1,49 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerButton;
+import net.minecraft.core.entity.monster.EntityCreeper;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityCreeperEntry extends EntityEntry<EntityCreeper>{
+    @Override
+    public void onTick(EntityCreeper entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityCreeper creeper) {
+        List<GuiButton> buttonList = new ArrayList<>();
+        boolean isCharged = creeper.getPowered();
+        GuiListenerButton chargedToggle = new GuiListenerButton(-1, - 120, 0, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.creeper.button.charged", isCharged));
+        chargedToggle.setActionListener(() -> {
+            boolean isCharged1 = creeper.getPowered();
+            isCharged1 = !isCharged1;
+            creeper.getEntityData().set(17, (byte) (isCharged1 ? 1 : 0));
+            chargedToggle.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.creeper.button.charged", isCharged1);
+        });
+        buttonList.add(chargedToggle);
+        return buttonList;
+    }
+
+    @Override
+    public EntityCreeper getEntityInstance(Minecraft mc, World world) {
+        return new EntityCreeper(world);
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntry.java
new file mode 100644
index 000000000..7cfbb1c7c
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityEntry.java
@@ -0,0 +1,19 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.core.entity.Entity;
+import net.minecraft.core.world.World;
+
+import java.util.List;
+
+public abstract class EntityEntry<T extends Entity>{
+    public static final EntityEntry<Entity> blankEntry = new BlankEntry();
+    public EntityEntry(){}
+    public abstract void onTick(T entity);
+    public abstract List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, T entity);
+    public abstract T getEntityInstance(Minecraft mc, World world);
+    public abstract void onOpen();
+    public abstract void onClose();
+}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityFallingSandEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityFallingSandEntry.java
new file mode 100644
index 000000000..1b7a020b0
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityFallingSandEntry.java
@@ -0,0 +1,64 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import net.minecraft.client.gui.modelviewer.elements.GuiTextCycle;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.entity.EntityFallingSand;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityFallingSandEntry extends EntityEntry<EntityFallingSand>{
+    @Override
+    public void onTick(EntityFallingSand entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityFallingSand sand) {
+        GuiTextCycle<Integer> blockIdCycle = new GuiTextCycle<Integer>(parentScreen, mc.fontRenderer, - 120, 0, 120, 20, sand.blockID) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return GuiModelViewer.cycleBlockId(current, offset);
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = Integer.parseInt(s);
+                    if (Block.blocksList[id] != null) return id;
+                } catch (Exception ignored){}
+                return sand.blockID;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        blockIdCycle.textField.setPrefaceText("ID: ");
+        blockIdCycle.textField.setPlaceholder("Block ID");
+        blockIdCycle.setOnValueChanged(() -> sand.blockID = blockIdCycle.getCurrentElement());
+        return new ArrayList<GuiButton>(){{add(blockIdCycle);}};
+    }
+
+    @Override
+    public EntityFallingSand getEntityInstance(Minecraft mc, World world) {
+        return new EntityFallingSand(world);
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityFireflyEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityFireflyEntry.java
new file mode 100644
index 000000000..a0d1e6e57
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityFireflyEntry.java
@@ -0,0 +1,66 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListSelectorButton;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerSlider;
+import net.minecraft.core.entity.animal.EntityFireflyCluster;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class EntityFireflyEntry extends EntityEntry<EntityFireflyCluster>{
+    @Override
+    public void onTick(EntityFireflyCluster fireflyCluster) {
+        Random random = fireflyCluster.world.rand;
+        double dy = (random.nextFloat() * 2F - 1F) * (fireflyCluster.bbHeight);
+        double dx = (random.nextFloat() * 2F - 1F) * (fireflyCluster.bbWidth);
+        double dz = (random.nextFloat() * 2F - 1F) * (fireflyCluster.bbWidth);
+
+        if (random.nextInt(Math.max(1, 10 - fireflyCluster.getFireflyCount())) == 0) {
+            fireflyCluster.world.spawnParticle(fireflyCluster.getColor().getParticleName(), fireflyCluster.x + dx, fireflyCluster.y + dy, fireflyCluster.z + dz, fireflyCluster.xd, fireflyCluster.yd, fireflyCluster.zd, 99999D);
+        }
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityFireflyCluster fireflyCluster) {
+        List<GuiButton> buttonList = new ArrayList<>();
+        GuiListenerSlider slider = new GuiListenerSlider(-1, - 120, 0, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.fireflycluster.slider.size", 0), 0f);
+        slider.setOnValueChanged(() -> {
+            fireflyCluster.setClusterSize((int) (slider.sliderValue * (fireflyCluster.maxClusterSize)));
+            slider.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.fireflycluster.slider.size", fireflyCluster.getClusterSize());
+        });
+
+        GuiListSelectorButton<EntityFireflyCluster.FireflyColor> button = new GuiListSelectorButton<EntityFireflyCluster.FireflyColor>(-1, - 120, slider.yPosition + 21, 120, 20, I18n.getInstance().translateKey("model.category.entity.fireflycluster.button.cycle"), EntityFireflyCluster.FireflyColor.fireFlyColors.values(), EntityFireflyCluster.FireflyColor.GREEN) {
+            @Override
+            public String getNameFromElement(EntityFireflyCluster.FireflyColor element) {
+                return element.getParticleName();
+            }
+        };
+        button.setActionListener(() -> fireflyCluster.setColor(button.getCurrentElement()));
+        buttonList.add(slider);
+        buttonList.add(button);
+        return buttonList;
+    }
+
+    @Override
+    public EntityFireflyCluster getEntityInstance(Minecraft mc, World world) {
+        EntityFireflyCluster cluster = new EntityFireflyCluster(world);
+        cluster.setClusterSize(0);
+        return cluster;
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityItemEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityItemEntry.java
new file mode 100644
index 000000000..aefb08c79
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityItemEntry.java
@@ -0,0 +1,105 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerSlider;
+import net.minecraft.client.gui.modelviewer.elements.GuiTextCycle;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.entity.EntityItem;
+import net.minecraft.core.item.Item;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityItemEntry extends EntityEntry<EntityItem>{
+    @Override
+    public void onTick(EntityItem entityItem) {
+        entityItem.age++;
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityItem entityItem) {
+        List<GuiButton> buttonList = new ArrayList<>();
+        entityItem.item = Block.stone.getDefaultStack();
+        GuiTextCycle<Integer> itemIdCycle = new GuiTextCycle<Integer>(parentScreen, mc.fontRenderer, - 120, 0, 120, 20, 1) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return GuiModelViewer.cycleItemId(current, offset);
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = Integer.parseInt(s);
+                    return MathHelper.clamp(id, 0, Item.itemsList.length);
+                } catch (Exception ignored){}
+                return entityItem.item.itemID;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        itemIdCycle.textField.setPrefaceText("ID: ");
+        itemIdCycle.textField.setPlaceholder("Item ID");
+
+        GuiTextCycle<Integer> metaCycle = new GuiTextCycle<Integer>(parentScreen, mc.fontRenderer, - 120, itemIdCycle.yPosition + 21, 120, 20, 0) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return (current + offset) & 0x3FFF;
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = Integer.parseInt(s);
+                    return MathHelper.clamp(id, 0, 0x3FFF);
+                } catch (Exception ignored){}
+                return entityItem.item.getMetadata();
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        metaCycle.textField.setPrefaceText("Meta: ");
+        metaCycle.textField.setPlaceholder("Meta");
+        GuiListenerSlider sizeSlider = new GuiListenerSlider(-1, - 120, metaCycle.yPosition + 21,120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.item.slider.size", 1), 1/64f);
+
+        itemIdCycle.setOnValueChanged(() -> entityItem.item = new ItemStack(itemIdCycle.getCurrentElement(), (int) (sizeSlider.sliderValue * 64), metaCycle.getCurrentElement()));
+        metaCycle.setOnValueChanged(() -> entityItem.item = new ItemStack(itemIdCycle.getCurrentElement(), (int) (sizeSlider.sliderValue * 64), metaCycle.getCurrentElement()));
+
+        sizeSlider.setOnValueChanged(() -> {
+            entityItem.item.stackSize = (int) (sizeSlider.sliderValue * 64);
+            sizeSlider.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.item.slider.size", entityItem.item.stackSize);
+        });
+
+        buttonList.add(itemIdCycle);
+        buttonList.add(metaCycle);
+        buttonList.add(sizeSlider);
+        return buttonList;
+    }
+
+    @Override
+    public EntityItem getEntityInstance(Minecraft mc, World world) {
+        return new EntityItem(world);
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityMinecartEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityMinecartEntry.java
new file mode 100644
index 000000000..55ad456a2
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityMinecartEntry.java
@@ -0,0 +1,44 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerButton;
+import net.minecraft.core.entity.vehicle.EntityMinecart;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+import org.lwjgl.input.Keyboard;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityMinecartEntry extends EntityEntry<EntityMinecart>{
+    @Override
+    public void onTick(EntityMinecart entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityMinecart minecart) {
+        GuiListenerButton button = new GuiListenerButton(-1, - 120, 0, 120, 20, I18n.getInstance().translateKey("model.category.entity.minecart.button.cycle"));
+        button.setActionListener(() -> minecart.minecartType = (minecart.minecartType + 3 + (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) ? -1 : 1)) % 3);
+        return new ArrayList<GuiButton>(){{add(button);}};
+    }
+
+    @Override
+    public EntityMinecart getEntityInstance(Minecraft mc, World world) {
+        EntityMinecart minecart = new EntityMinecart(world);
+        minecart.yRot = 270;
+        return minecart;
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityPaintingEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityPaintingEntry.java
new file mode 100644
index 000000000..df97616ca
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityPaintingEntry.java
@@ -0,0 +1,46 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerSlider;
+import net.minecraft.core.entity.EntityPainting;
+import net.minecraft.core.enums.ArtType;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityPaintingEntry extends EntityEntry<EntityPainting>{
+    @Override
+    public void onTick(EntityPainting entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityPainting painting) {
+        GuiListenerSlider slider = new GuiListenerSlider(-1, - 120, 0, 120, 20, painting.art.key, 0f);
+        slider.setOnValueChanged(() -> {
+            painting.art = ArtType.values.get((int) (slider.sliderValue * (ArtType.values.size() - 1)));
+            slider.displayString = painting.art.key;
+        });
+        return new ArrayList<GuiButton>(){{add(slider);}};
+    }
+
+    @Override
+    public EntityPainting getEntityInstance(Minecraft mc, World world) {
+        EntityPainting painting = new EntityPainting(world);
+        painting.setDirection(2);
+        return painting;
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntitySheepEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntitySheepEntry.java
new file mode 100644
index 000000000..2005f4784
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntitySheepEntry.java
@@ -0,0 +1,52 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerSlider;
+import net.minecraft.core.entity.animal.EntitySheep;
+import net.minecraft.core.item.ItemDye;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntitySheepEntry extends EntityEntry<EntitySheep>{
+    @Override
+    public void onTick(EntitySheep entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntitySheep sheep) {
+        List<GuiButton> buttonList = new ArrayList<>();
+        GuiListenerSlider slider = new GuiListenerSlider(-1, - 120, 0, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.sheep.slider.color", "White"), 0f);
+        slider.setOnValueChanged(() -> {
+            sheep.setFleeceColor((int) (slider.sliderValue * 15));
+            String color = ItemDye.dyeColors[15 - sheep.getFleeceColor()];
+            String c = String.valueOf(color.charAt(0));
+            color = c.toUpperCase() + color.substring(1);
+            slider.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.sheep.slider.color", color);
+        });
+        buttonList.add(slider);
+        return buttonList;
+    }
+
+    @Override
+    public EntitySheep getEntityInstance(Minecraft mc, World world) {
+        EntitySheep sheep = new EntitySheep(world);
+        sheep.setFleeceColor(0);
+        return sheep;
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntitySlimeEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntitySlimeEntry.java
new file mode 100644
index 000000000..2bbd32a5e
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntitySlimeEntry.java
@@ -0,0 +1,46 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerSlider;
+import net.minecraft.core.entity.monster.EntitySlime;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntitySlimeEntry extends EntityEntry<EntitySlime>{
+    @Override
+    public void onTick(EntitySlime entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntitySlime entity) {
+        List<GuiButton> buttonList = new ArrayList<>();
+        GuiListenerSlider slider = new GuiListenerSlider(-1, - 120, 0, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.slime.slider.size", 1), 0f);
+        slider.setOnValueChanged(() -> {
+            entity.setSlimeSize((int) (slider.sliderValue * 4) + 1);
+            slider.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.slime.slider.size", entity.getSlimeSize());
+        });
+        buttonList.add(slider);
+        return buttonList;
+    }
+
+    @Override
+    public EntitySlime getEntityInstance(Minecraft mc, World world) {
+        return new EntitySlime(world);
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityTNTEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityTNTEntry.java
new file mode 100644
index 000000000..abe344c0c
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityTNTEntry.java
@@ -0,0 +1,45 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerSlider;
+import net.minecraft.core.entity.EntityTNT;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityTNTEntry extends EntityEntry<EntityTNT>{
+    @Override
+    public void onTick(EntityTNT entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityTNT tnt) {
+        tnt.fuse = 80;
+        GuiListenerSlider slider = new GuiListenerSlider(-1, - 120, 0, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.tnt.slider.fuse", 80), 1f);
+        slider.setOnValueChanged(() -> {
+            tnt.fuse = (int) (slider.sliderValue * 80);
+            slider.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.tnt.slider.fuse", tnt.fuse);
+        });
+        return new ArrayList<GuiButton>(){{add(slider);}};
+    }
+
+    @Override
+    public EntityTNT getEntityInstance(Minecraft mc, World world) {
+        return new EntityTNT(world);
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityWolfEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityWolfEntry.java
new file mode 100644
index 000000000..3cc3a7c9e
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/entity/EntityWolfEntry.java
@@ -0,0 +1,169 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.entity;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import net.minecraft.client.gui.modelviewer.elements.GuiListSelectorButton;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerButton;
+import net.minecraft.client.gui.modelviewer.elements.GuiTextCycle;
+import net.minecraft.core.entity.animal.EntityWolf;
+import net.minecraft.core.item.Item;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.item.material.ArmorMaterial;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityWolfEntry extends EntityEntry<EntityWolf>{
+    private static final List<ArmorMaterial> armorMaterials = new ArrayList<>(EntityWolf.ARMOR_MATERIALS.keySet());
+    static {
+        armorMaterials.add(null);
+    }
+
+    @Override
+    public void onTick(EntityWolf entity) {
+
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen, EntityWolf entityWolf) {
+        List<GuiButton> buttonList = new ArrayList<>();
+        boolean isTamed = entityWolf.isWolfTamed();
+        GuiListenerButton tamed = new GuiListenerButton(-1, - 120, 0, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.wolf.button.tamed", isTamed));
+        tamed.setActionListener(() -> {
+            boolean _tamed = !entityWolf.isWolfTamed();
+            entityWolf.setWolfTamed(_tamed);
+            tamed.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.wolf.button.tamed", _tamed);
+        });
+
+        boolean isSitting = entityWolf.isWolfSitting();
+        GuiListenerButton sitting = new GuiListenerButton(-1, - 120, tamed.yPosition + 21, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.wolf.button.sitting", isSitting));
+        sitting.setActionListener(() -> {
+            boolean _sitting = !entityWolf.isWolfSitting();
+            entityWolf.setWolfSitting(_sitting);
+            sitting.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.wolf.button.sitting", _sitting);
+        });
+
+        boolean isAngry = entityWolf.isWolfAngry();
+        GuiListenerButton angry = new GuiListenerButton(-1, - 120, sitting.yPosition + 21, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.wolf.button.angry", isAngry));
+        angry.setActionListener(() -> {
+            boolean _angry = !entityWolf.isWolfAngry();
+            entityWolf.setWolfAngry(_angry);
+            angry.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.wolf.button.angry", _angry);
+        });
+
+        GuiListSelectorButton<ArmorMaterial> armor = new GuiListSelectorButton<ArmorMaterial>(-1, - 120, angry.yPosition + 21, 120, 20, I18n.getInstance().translateKey("model.category.entity.wolf.button.armor"), armorMaterials,null) {
+            @Override
+            public String getNameFromElement(ArmorMaterial element) {
+                return element == null ? "none" : element.name;
+            }
+        };
+        armor.setActionListener(() -> {
+            ArmorMaterial material = armor.getCurrentElement();
+            entityWolf.getEntityData().set(19, material == null ? "" : material.name);
+        });
+
+        entityWolf.setWolfHeldItem(null);
+        GuiListenerButton hasItem = new GuiListenerButton(-1, - 120, armor.yPosition + 21, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.entity.wolf.button.item", false));
+
+        GuiTextCycle<Integer> itemIdCycle = new GuiTextCycle<Integer>(parentScreen, mc.fontRenderer, - 120, hasItem.yPosition + 21, 120, 20, 1) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return GuiModelViewer.cycleItemId(current, offset);
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = Integer.parseInt(s);
+                    if (Item.itemsList[id] != null) return id;
+                } catch (Exception ignored){}
+                if (entityWolf.getWolfHeldItem() != null){
+                    return entityWolf.getWolfHeldItem().itemID;
+                }
+                return 0;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        itemIdCycle.enabled = false;
+        itemIdCycle.textField.setPrefaceText("ID: ");
+        itemIdCycle.textField.setPlaceholder("Item ID");
+
+        GuiTextCycle<Integer> metaCycle = new GuiTextCycle<Integer>(parentScreen, mc.fontRenderer, - 120, itemIdCycle.yPosition + 21, 120, 20, 0) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return (current + offset) & 0x3FFF;
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = Integer.parseInt(s);
+                    return MathHelper.clamp(id, 0, 0x3FFF);
+                } catch (Exception ignored){}
+                if (entityWolf.getWolfHeldItem() != null){
+                    return entityWolf.getWolfHeldItem().getMetadata();
+                }
+                return 0;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        metaCycle.enabled = false;
+        metaCycle.textField.setPrefaceText("Meta: ");
+        metaCycle.textField.setPlaceholder("Meta");
+
+        itemIdCycle.setOnValueChanged(() -> entityWolf.setWolfHeldItem(new ItemStack(itemIdCycle.getCurrentElement(), 1, metaCycle.getCurrentElement())));
+        metaCycle.setOnValueChanged(() -> entityWolf.setWolfHeldItem(new ItemStack(itemIdCycle.getCurrentElement(), 1, metaCycle.getCurrentElement())));
+        hasItem.setActionListener(() -> {
+            boolean _hasItem = entityWolf.getWolfHeldItem() != null;
+            if (_hasItem){
+                entityWolf.setWolfHeldItem(null);
+                itemIdCycle.enabled = false;
+                metaCycle.enabled = false;
+            } else {
+                entityWolf.setWolfHeldItem(new ItemStack(itemIdCycle.getCurrentElement(), 1, metaCycle.getCurrentElement()));
+                itemIdCycle.enabled = true;
+                metaCycle.enabled = true;
+            }
+            hasItem.displayString = I18n.getInstance().translateKeyAndFormat("model.category.entity.wolf.button.item", !_hasItem);
+        });
+
+        buttonList.add(tamed);
+        buttonList.add(sitting);
+        buttonList.add(angry);
+        buttonList.add(armor);
+        buttonList.add(hasItem);
+        buttonList.add(itemIdCycle);
+        buttonList.add(metaCycle);
+        return buttonList;
+    }
+
+    @Override
+    public EntityWolf getEntityInstance(Minecraft mc, World world) {
+        EntityWolf wolf = new EntityWolf(world);
+        wolf.setWolfHeldItem(null);
+        return wolf;
+    }
+
+    @Override
+    public void onOpen() {
+
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/BlockFXEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/BlockFXEntry.java
new file mode 100644
index 000000000..10fcb96ff
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/BlockFXEntry.java
@@ -0,0 +1,92 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.particle;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.fx.EntityDiggingFX;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import net.minecraft.client.gui.modelviewer.elements.GuiTextCycle;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.item.Item;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.World;
+
+import java.util.List;
+
+public class BlockFXEntry extends GenericFXEntry{
+    protected int blockId;
+    protected int meta;
+
+    public BlockFXEntry() {
+        super("block");
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen) {
+        List<GuiButton> buttonList = super.getEntryButtons(mc, parentScreen);
+        GuiTextCycle<Integer> blockIdCycle = new GuiTextCycle<Integer>(parentScreen, mc.fontRenderer, - 120, buttonList.get(buttonList.size()-1).yPosition + 21, 120, 20, blockId) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return GuiModelViewer.cycleBlockId(current, offset);
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = Integer.parseInt(s);
+                    return MathHelper.clamp(id, 0, Item.itemsList.length);
+                } catch (Exception ignored){}
+                return blockId;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        blockIdCycle.textField.setPrefaceText("ID: ");
+        blockIdCycle.textField.setPlaceholder("Block ID");
+        blockIdCycle.setOnValueChanged(() -> blockId = blockIdCycle.getCurrentElement());
+        buttonList.add(blockIdCycle);
+
+        GuiTextCycle<Integer> metaCycle = new GuiTextCycle<Integer>(parentScreen, mc.fontRenderer, - 120, blockIdCycle.yPosition + 21, 120, 20, 0) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return (current + offset) & 0x3FFF;
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = Integer.parseInt(s);
+                    return MathHelper.clamp(id, 0, 0x3FFF);
+                } catch (Exception ignored){}
+                return meta;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        metaCycle.textField.setPrefaceText("Meta: ");
+        metaCycle.textField.setPlaceholder("Meta");
+        metaCycle.setOnValueChanged(() -> meta = metaCycle.getCurrentElement());
+        buttonList.add(metaCycle);
+
+        return buttonList;
+    }
+
+    @Override
+    public void spawnParticle(Minecraft mc, World world, double x, double y, double z) {
+        mc.effectRenderer.addEffect(new EntityDiggingFX(world, x, y, z, motionX,motionY,motionZ, Block.getBlock(blockId), Side.BOTTOM.getId(), meta));
+    }
+
+    @Override
+    public void onOpen() {
+        blockId = 1;
+    }
+
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/BubbleFXEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/BubbleFXEntry.java
new file mode 100644
index 000000000..46a8587b5
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/BubbleFXEntry.java
@@ -0,0 +1,15 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.particle;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.fx.EntityBubbleFX;
+import net.minecraft.core.world.World;
+
+public class BubbleFXEntry extends GenericFXEntry{
+    public BubbleFXEntry() {
+        super("bubble");
+    }
+    @Override
+    public void spawnParticle(Minecraft mc, World world, double x, double y, double z) {
+        mc.effectRenderer.addEffect(new EntityBubbleFX(world, x, y, z, motionX, motionY, motionZ, false));
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/GenericFXEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/GenericFXEntry.java
new file mode 100644
index 000000000..0dde12094
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/GenericFXEntry.java
@@ -0,0 +1,82 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.particle;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerTextField;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class GenericFXEntry extends ParticleEntry{
+    public final String particleID;
+    protected final String overrideName;
+    protected double motionX;
+    protected double motionY;
+    protected double motionZ;
+
+    public GenericFXEntry(String particleID){
+        this(particleID, null);
+    }
+    public GenericFXEntry(String particleID, String overrideName){
+        this.particleID = Objects.requireNonNull(particleID);
+        this.overrideName = overrideName;
+    }
+    @Override
+    public String getParticleName(I18n translator) {
+        if (overrideName != null){
+            return overrideName;
+        }
+        return particleID;
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen) {
+        List<GuiButton> buttons = new ArrayList<>();
+        GuiListenerTextField mxField = new GuiListenerTextField(parentScreen, mc.fontRenderer, -120, 0, 120, 20, String.valueOf(motionX), "Motion X");
+        mxField.setPrefaceText("Motion X: ");
+        mxField.setOnValueChanged(() ->{
+            try {
+                motionX = Double.parseDouble(mxField.getText());
+            } catch (Exception ignored){}
+        });
+        GuiListenerTextField myField = new GuiListenerTextField(parentScreen, mc.fontRenderer, -120, mxField.yPosition + 21, 120, 20, String.valueOf(motionY), "Motion Y");
+        myField.setPrefaceText("Motion Y: ");
+        myField.setOnValueChanged(() ->{
+            try {
+                motionY = Double.parseDouble(myField.getText());
+            } catch (Exception ignored){}
+        });
+        GuiListenerTextField mzField = new GuiListenerTextField(parentScreen, mc.fontRenderer, -120, myField.yPosition + 21, 120, 20, String.valueOf(motionZ), "Motion Z");
+        mzField.setPrefaceText("Motion Z: ");
+        mzField.setOnValueChanged(() ->{
+            try {
+                motionZ = Double.parseDouble(mzField.getText());
+            } catch (Exception ignored){}
+        });
+        buttons.add(mxField);
+        buttons.add(myField);
+        buttons.add(mzField);
+        return buttons;
+    }
+
+    @Override
+    public void spawnParticle(Minecraft mc, World world, double x, double y, double z) {
+        world.spawnParticle(particleID, x, y, z, motionX, motionY, motionZ);
+    }
+
+    @Override
+    public void onOpen() {
+        motionX = 0;
+        motionY = 0;
+        motionZ = 0;
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ItemFXEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ItemFXEntry.java
new file mode 100644
index 000000000..be56276f7
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ItemFXEntry.java
@@ -0,0 +1,80 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.particle;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.fx.EntityItemFX;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiTextCycle;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.item.Item;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ItemFXEntry extends ParticleEntry{
+    protected int itemID;
+    @Override
+    public String getParticleName(I18n translator) {
+        return "item";
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen) {
+        GuiTextCycle<Integer> itemIdCycle = new GuiTextCycle<Integer>(parentScreen, mc.fontRenderer, - 120, 0, 120, 20, itemID) {
+            @Override
+            public Integer cycleElement(Integer current, int offset) {
+                return cycleItemId(current, offset);
+            }
+
+            @Override
+            public Integer getElementFromString(String s) {
+                try {
+                    int id = Integer.parseInt(s);
+                    return MathHelper.clamp(id, 0, Item.itemsList.length);
+                } catch (Exception ignored){}
+                return itemID;
+            }
+
+            @Override
+            public String getNameFromElement(Integer element) {
+                return String.valueOf(element);
+            }
+        };
+        itemIdCycle.textField.setPrefaceText("ID: ");
+        itemIdCycle.textField.setPlaceholder("Item ID");
+        itemIdCycle.setOnValueChanged(() -> itemID = itemIdCycle.getCurrentElement());
+        return new ArrayList<GuiButton>(){
+            {
+                add(itemIdCycle);
+            }
+        };
+    }
+
+    @Override
+    public void spawnParticle(Minecraft mc, World world, double x, double y, double z) {
+        mc.effectRenderer.addEffect(new EntityItemFX(world, x, y, z, Item.itemsList[itemID]));
+    }
+
+    @Override
+    public void onOpen() {
+        itemID = 16384;
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+    private int cycleItemId(int itemId, int offset){
+        int numItems = Item.itemsList.length - Block.blocksList.length;
+
+        int _itemId = MathHelper.clamp(itemId - numItems, 0, numItems);
+        int id = (_itemId + numItems + offset) % numItems;
+        while (Item.itemsList[id + Block.blocksList.length] == null){
+            id = (id + (int) Math.signum(offset) + numItems) % numItems;
+        }
+        return id + Block.blocksList.length;
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/LeafFXEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/LeafFXEntry.java
new file mode 100644
index 000000000..fd9ebfdef
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/LeafFXEntry.java
@@ -0,0 +1,15 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.particle;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.fx.EntityLeafFX;
+import net.minecraft.core.world.World;
+
+public class LeafFXEntry extends GenericFXEntry{
+    public LeafFXEntry() {
+        super("fallingleaf");
+    }
+    @Override
+    public void spawnParticle(Minecraft mc, World world, double x, double y, double z) {
+        mc.effectRenderer.addEffect(new EntityLeafFX(world, x, y, z, motionX, motionY, motionZ));
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/NoteFXEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/NoteFXEntry.java
new file mode 100644
index 000000000..6df504b4b
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/NoteFXEntry.java
@@ -0,0 +1,49 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.particle;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.fx.EntityNoteFX;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerSlider;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NoteFXEntry extends ParticleEntry{
+    protected int note = 0;
+    protected final int maxNote = 24;
+    @Override
+    public String getParticleName(I18n translator) {
+        return "note";
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen) {
+        GuiListenerSlider noteSlider = new GuiListenerSlider(-1, -120, 0, 120, 20, I18n.getInstance().translateKeyAndFormat("model.category.particle.note.slider", getNoteString(note)), ((float)note)/maxNote);
+        noteSlider.setOnValueChanged(() ->{
+            note = (int) (noteSlider.sliderValue * maxNote);
+            noteSlider.displayString = I18n.getInstance().translateKeyAndFormat("model.category.particle.note.slider", getNoteString(note));
+        });
+        return new ArrayList<GuiButton>(){{add(noteSlider);}};
+    }
+    private String getNoteString(int note){
+        return (Integer.toHexString(note).length() == 1) ? "0"+Integer.toHexString(note) : Integer.toHexString(note);
+    }
+
+    @Override
+    public void spawnParticle(Minecraft mc, World world, double x, double y, double z) {
+        mc.effectRenderer.addEffect(new EntityNoteFX(world, x, y, z, (double) note / 24D, 0.0D, 0.0D));
+    }
+
+    @Override
+    public void onOpen() {
+        note = 0;
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ParticleEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ParticleEntry.java
new file mode 100644
index 000000000..95d6b8a76
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/ParticleEntry.java
@@ -0,0 +1,17 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.particle;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+
+import java.util.List;
+
+public abstract class ParticleEntry {
+    public abstract String getParticleName(I18n translator);
+    public abstract List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen);
+    public abstract void spawnParticle(Minecraft mc, World world, double x, double y, double z);
+    public abstract void onOpen();
+    public abstract void onClose();
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/RedDustFXEntry.java b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/RedDustFXEntry.java
new file mode 100644
index 000000000..896e066a2
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/categories/entries/particle/RedDustFXEntry.java
@@ -0,0 +1,88 @@
+package net.minecraft.client.gui.modelviewer.categories.entries.particle;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.fx.EntityReddustFX;
+import net.minecraft.client.gui.GuiButton;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.modelviewer.elements.GuiListenerTextField;
+import net.minecraft.core.lang.I18n;
+import net.minecraft.core.world.World;
+import org.lwjgl.input.Keyboard;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class RedDustFXEntry extends ParticleEntry{
+    private int red = 0;
+    private int green = 0;
+    private int blue = 0;
+    @Override
+    public String getParticleName(I18n translator) {
+        return "reddust";
+    }
+
+    @Override
+    public List<GuiButton> getEntryButtons(Minecraft mc, GuiScreen parentScreen) {
+        GuiListenerTextField rField = new GuiListenerTextField(parentScreen, mc.fontRenderer, -120, 0, 40, 20, String.valueOf(red), "Red");
+        rField.setPrefaceText("R: ");
+        rField.setKeyListener(key -> {
+            try {
+                red = Integer.parseInt(rField.getText());
+            } catch (Exception ignored){}
+        });
+        rField.setActionListener(() -> {
+            if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)){
+                rField.setText(String.valueOf(0));
+                red = 0;
+            }
+        });
+        GuiListenerTextField gField = new GuiListenerTextField(parentScreen, mc.fontRenderer, -80, 0, 40, 20, String.valueOf(green), "Green");
+        gField.setPrefaceText("G: ");
+        gField.setKeyListener(key -> {
+            try {
+                green = Integer.parseInt(gField.getText());
+            } catch (Exception ignored){}
+        });
+        gField.setActionListener(() -> {
+            if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)){
+                gField.setText(String.valueOf(0));
+                green = 0;
+            }
+        });
+        GuiListenerTextField bField = new GuiListenerTextField(parentScreen, mc.fontRenderer, -40, 0, 40, 20, String.valueOf(blue), "Blue");
+        bField.setPrefaceText("B: ");
+        bField.setKeyListener(key -> {
+            try {
+                blue = Integer.parseInt(bField.getText());
+            } catch (Exception ignored){}
+        });
+        bField.setActionListener(() -> {
+            if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)){
+                bField.setText(String.valueOf(0));
+                blue = 0;
+            }
+        });
+        return new ArrayList<GuiButton>(){{
+            add(rField);
+            add(gField);
+            add(bField);
+        }};
+    }
+
+    @Override
+    public void spawnParticle(Minecraft mc, World world, double x, double y, double z) {
+        mc.effectRenderer.addEffect(new EntityReddustFX(world, x, y, z, red/255f, green/255f, blue/255f));
+    }
+
+    @Override
+    public void onOpen() {
+        red = 0;
+        green = 0;
+        blue = 0;
+    }
+
+    @Override
+    public void onClose() {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListSelectorButton.java b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListSelectorButton.java
new file mode 100644
index 000000000..5d7bb9166
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListSelectorButton.java
@@ -0,0 +1,47 @@
+package net.minecraft.client.gui.modelviewer.elements;
+
+import net.minecraft.client.Minecraft;
+import org.lwjgl.input.Keyboard;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public abstract class GuiListSelectorButton<T> extends GuiListenerButton{
+    public final List<T> list;
+    private int index;
+    private final String formattedText;
+    private final T defaultElement;
+    public GuiListSelectorButton(int id, int xPosition, int yPosition, int width, int height, String formattedText, Collection<T> collection, T initialElement) {
+        super(id, xPosition, yPosition, width, height, "");
+        displayString = String.format(formattedText, getNameFromElement(initialElement));
+        this.defaultElement = initialElement;
+        this.formattedText = formattedText;
+        this.list = new ArrayList<>(collection);
+        this.index = this.list.indexOf(initialElement);
+    }
+    @Override
+    public void onClick(Minecraft mc, int mouseX, int mouseY) {
+        if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)){
+            resetValue();
+        } else {
+            offsetId(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) ? -1 : 1);
+        }
+        displayString = String.format(formattedText, getNameFromElement(getCurrentElement()));
+        super.onClick(mc, mouseX, mouseY);
+    }
+    public T getCurrentElement(){
+        return list.get(index);
+    }
+    private void offsetId(int offset){
+        int _index = index;
+        index = (index + list.size() + offset) % list.size();
+        if (_index != index){
+            onValueChanged();
+        }
+    }
+    public void resetValue(){
+        index = list.indexOf(defaultElement);
+    }
+    public abstract String getNameFromElement(T element);
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListenerButton.java b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListenerButton.java
new file mode 100644
index 000000000..547793dfb
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListenerButton.java
@@ -0,0 +1,61 @@
+package net.minecraft.client.gui.modelviewer.elements;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiButton;
+
+public class GuiListenerButton extends GuiButton implements IListenerElement {
+    protected IActionListener action;
+    protected IKeyListener keyListener;
+    protected Runnable onValueChanged;
+    public GuiListenerButton(int id, int xPosition, int yPosition, String text) {
+        super(id, xPosition, yPosition, text);
+    }
+
+    public GuiListenerButton(int id, int xPosition, int yPosition, int width, int height, String text) {
+        super(id, xPosition, yPosition, width, height, text);
+    }
+    @Override
+    public boolean mouseClicked(Minecraft mc, int mouseX, int mouseY) {
+        boolean flag = super.mouseClicked(mc, mouseX, mouseY);
+        if (flag){
+            onClick(mc, mouseX, mouseY);
+        }
+        return flag;
+    }
+    protected void onClick(Minecraft mc, int mouseX, int mouseY){
+        if (action != null){
+            action.onInteract();
+            onValueChanged();
+        }
+    }
+    @Override
+    public void setActionListener(IActionListener listener) {
+        action = listener;
+    }
+
+    @Override
+    public void setKeyListener(IKeyListener listener) {
+        keyListener = listener;
+    }
+    @Override
+    public void setOnValueChanged(Runnable runnable){
+        onValueChanged = runnable;
+    }
+
+    @Override
+    public void onKeyTyped(char c, int key) {
+        if (keyListener != null){
+            keyListener.onKeyPressed(key);
+        }
+    }
+
+    @Override
+    public void onValueChanged() {
+        if (onValueChanged != null){
+            onValueChanged.run();
+        }
+    }
+    public void tick(){
+
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListenerSlider.java b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListenerSlider.java
new file mode 100644
index 000000000..f59a43df4
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListenerSlider.java
@@ -0,0 +1,69 @@
+package net.minecraft.client.gui.modelviewer.elements;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiSlider;
+import net.minecraft.client.option.FloatOption;
+
+public class GuiListenerSlider extends GuiSlider implements IListenerElement {
+    private IActionListener action;
+    private IKeyListener keyListener;
+    private Runnable onValueChanged;
+    public GuiListenerSlider(int id, int xPosition, int yPosition, FloatOption floatOption) {
+        super(id, xPosition, yPosition, floatOption);
+    }
+
+    public GuiListenerSlider(int id, int xPosition, int yPosition, int width, int height, FloatOption floatOption) {
+        super(id, xPosition, yPosition, width, height, floatOption);
+    }
+
+    public GuiListenerSlider(int id, int xPosition, int yPosition, int width, int height, String text, float defaultValue) {
+        super(id, xPosition, yPosition, width, height, text, defaultValue);
+    }
+    @Override
+    public boolean mouseClicked(Minecraft mc, int mouseX, int mouseY) {
+        float _val = sliderValue;
+        boolean flag = super.mouseClicked(mc, mouseX, mouseY);
+        if (flag && action != null){
+            action.onInteract();
+            if (sliderValue != _val){
+                onValueChanged();
+            }
+        }
+        return flag;
+    }
+    @Override
+    public void mouseDragged(Minecraft mc, int mouseX, int mouseY) {
+        float _val = sliderValue;
+        super.mouseDragged(mc, mouseX, mouseY);
+        if (sliderValue != _val){
+            onValueChanged();
+        }
+    }
+
+    @Override
+    public void setActionListener(IActionListener listener) {
+        action = listener;
+    }
+
+    @Override
+    public void setKeyListener(IKeyListener listener) {
+        keyListener = listener;
+    }
+    @Override
+    public void setOnValueChanged(Runnable runnable){
+        onValueChanged = runnable;
+    }
+    @Override
+    public void onKeyTyped(char c, int key) {
+        if (keyListener != null){
+            keyListener.onKeyPressed(key);
+        }
+    }
+
+    @Override
+    public void onValueChanged() {
+        if (onValueChanged != null){
+            onValueChanged.run();
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListenerTextField.java b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListenerTextField.java
new file mode 100644
index 000000000..389d185c9
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiListenerTextField.java
@@ -0,0 +1,187 @@
+package net.minecraft.client.gui.modelviewer.elements;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.text.ITextField;
+import net.minecraft.client.gui.text.TextFieldEditor;
+import net.minecraft.client.render.FontRenderer;
+import org.lwjgl.input.Keyboard;
+
+public class GuiListenerTextField extends GuiListenerButton implements ITextField {
+    private final FontRenderer fontRenderer;
+    private String text = "";
+    private String prefaceText = "";
+    private int maxStringLength;
+    private int cursorCounter;
+    public boolean isFocused;
+    public boolean isEnabled;
+    public boolean removeTextOnClick = false;
+    public GuiScreen parent;
+    private ITextChangeListener textChangeListener;
+    private String placeholder;
+    public boolean drawBackground = true;
+    public final TextFieldEditor editor;
+
+    public GuiListenerTextField(GuiScreen parent, FontRenderer fontrenderer, int xPosition, int yPosition, int width, int height, String defaultText, String placeholder)
+    {
+        super(-1, xPosition, yPosition, width, height, "");
+        playSound = false;
+        isFocused = false;
+        isEnabled = true;
+        this.parent = parent;
+        fontRenderer = fontrenderer;
+        this.editor = new TextFieldEditor(this);
+        this.placeholder = placeholder;
+        setText(defaultText);
+        editor.setCursor(10000);
+    }
+    public void setPrefaceText(String prefaceText){
+        this.prefaceText = prefaceText;
+    }
+
+    @Override
+    public void setText(String text)
+    {
+        if (text == null) editor.setCursor(0);
+        else if (text.length() < editor.getCursor())
+        {
+            editor.setCursor(text.length());
+        }
+        this.text = text;
+        if(textChangeListener != null) textChangeListener.textChanged(this);
+    }
+
+    @Override
+    public String getText()
+    {
+        return text;
+    }
+
+    public void setPlaceholder(String placeholder) {
+        this.placeholder = placeholder;
+    }
+
+    @Override
+    public void tick()
+    {
+        cursorCounter++;
+    }
+    @Override
+    public void onKeyTyped(char c, int key)
+    {
+        if(!isEnabled || !isFocused) {return;}
+        if(key == Keyboard.KEY_TAB) {
+            if (parent != null) {
+                parent.selectNextField();
+            }
+        }
+        if(editor.handleInput(key, c)) {
+            if(textChangeListener != null) textChangeListener.textChanged(this);
+            if (keyListener != null) keyListener.onKeyPressed(key);
+            onValueChanged();
+        }
+    }
+
+    @Override
+    public boolean mouseClicked(Minecraft mc, int mouseX, int mouseY)
+    {
+        boolean flag = super.mouseClicked(mc, mouseX, mouseY);
+        setFocused(flag);
+        return flag;
+    }
+    protected void onClick(Minecraft mc, int mouseX, int mouseY){
+        if(removeTextOnClick) {
+            setText("");
+        }
+        super.onClick(mc, mouseX, mouseY);
+    }
+
+    public void setFocused(boolean flag)
+    {
+        if(flag && !isFocused)
+        {
+            cursorCounter = 0;
+            editor.setCursor(10000);
+        }
+        isFocused = flag;
+    }
+
+    public void drawButton(Minecraft mc, int mouseX, int mouseY)
+    {
+        if (!visible) return;
+
+        if (drawBackground)
+        {
+            drawRect(xPosition - 1, yPosition - 1, xPosition + width + 1, yPosition + height + 1, 0xffa0a0a0);
+            drawRect(xPosition, yPosition, xPosition + width, yPosition + height, 0xff000000);
+        }
+        if (text.isEmpty() && !isFocused)
+        {
+            drawString(fontRenderer, placeholder, xPosition + 4, yPosition + (height - 8) / 2, 0x5f5f5f);
+        }
+
+        if(isEnabled)
+        {
+            boolean drawCursor = isFocused && (cursorCounter / 6) % 2 == 0;
+            int cursor = editor.getCursor();
+            int maxDisplayableChars = this.width / fontRenderer.getCharWidth('_');
+
+            if (!text.isEmpty() || isFocused){
+                if(prefaceText.length() + text.length() <= maxDisplayableChars-1){
+                    drawString(fontRenderer, prefaceText + text, xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
+                } else {
+                    //only draw the part of the string that's maxDisplayableChars chars around the cursor
+                    String newString = prefaceText + text;
+                    int begin = Math.max(0,cursor - maxDisplayableChars);
+                    int end = Math.max(maxDisplayableChars,Math.min(newString.length(),cursor));
+                    drawString(fontRenderer, newString.substring(begin, end), xPosition + 4, yPosition + (height - 8) / 2, 0xE0E0E0);
+                }
+            }
+            if (drawCursor)
+            {
+                String currentText = "";
+                if (!text.isEmpty() || isFocused){
+                    currentText = prefaceText + text;
+                }
+                int width = fontRenderer.getStringWidth(currentText);
+                if (cursor < text.length())
+                {
+                    width = fontRenderer.getStringWidth(text.substring(0, cursor)) + fontRenderer.getStringWidth(prefaceText);
+                }
+                if(width >= this.width-4){
+                    // width of the text box - the width of the last character
+                    width = (this.width-4) - fontRenderer.getStringWidth(currentText.substring(currentText.length()-2,currentText.length()-1));
+                }
+                drawString(fontRenderer, "_", xPosition + 4 + width, yPosition + (height - 8) / 2, 0xE0E0E0);
+            }
+        }
+        else
+        {
+            drawString(fontRenderer, text, xPosition + 4, yPosition + (height - 8) / 2, 0x707070);
+        }
+    }
+
+    public void setMaxStringLength(int i)
+    {
+        maxStringLength = i;
+    }
+    @Override
+    public int maxLength() {
+        return maxStringLength == 0 ? 1000 : maxStringLength;
+    }
+    @Override
+    public boolean isHovered(int mouseX, int mouseY)
+    {
+        // TODO replace with a better way of allowing keypresses to be recieved while focused
+        return isFocused || super.isHovered(mouseX, mouseY);
+    }
+
+    public void setTextChangeListener(ITextChangeListener textChangeListener) {
+        this.textChangeListener = textChangeListener;
+    }
+
+    public interface ITextChangeListener
+    {
+        void textChanged(GuiListenerTextField textField);
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiTextCycle.java b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiTextCycle.java
new file mode 100644
index 000000000..e1bafcda2
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/elements/GuiTextCycle.java
@@ -0,0 +1,114 @@
+package net.minecraft.client.gui.modelviewer.elements;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.render.FontRenderer;
+
+public abstract class GuiTextCycle<T> extends GuiListenerButton{
+    private T currentElement;
+    private final T defaultElement;
+    public final GuiListenerButton prevButton;
+    public final GuiListenerButton nextButton;
+    public final GuiListenerTextField textField;
+    public GuiTextCycle(GuiScreen parent, FontRenderer fontRenderer, int xPosition, int yPosition, int width, int height, T initialElement) {
+        super(-1, xPosition, yPosition, width, height, "");
+
+        textField = new GuiListenerTextField(parent, fontRenderer, 0, yPosition, width - height * 2 - 2, height, getNameFromElement(initialElement), "");
+        textField.setKeyListener(key -> {
+            String text = textField.getText();
+            setCurrentElement(getElementFromString(text));
+
+            // I have no idea why this is needed but whatever it works
+            textField.setText(text);
+            textField.editor.setCursor(999999);
+            textField.setText(text);
+        });
+
+        prevButton = new GuiListenerButton(-1, xPosition, yPosition, height, height, "<");
+        prevButton.setActionListener(() -> {
+            setCurrentElement(cycleElement(getCurrentElement(), -1));
+        });
+
+        textField.xPosition = prevButton.xPosition + prevButton.width + 1;
+
+        nextButton = new GuiListenerButton(-1, textField.xPosition + textField.width + 1, yPosition, height, height, ">");
+        nextButton.setActionListener(() -> {
+            setCurrentElement(cycleElement(getCurrentElement(), 1));
+        });
+
+        defaultElement = initialElement;
+        currentElement = initialElement;
+    }
+    public void reset(){
+        setCurrentElement(defaultElement);
+    }
+    public void setCurrentElement(T element){
+        boolean flag = currentElement != element;
+        currentElement = element;
+        if (flag) onValueChanged();
+    }
+    public abstract T cycleElement(T current, int offset);
+    public abstract T getElementFromString(String s);
+    public abstract String getNameFromElement(T element);
+    public T getCurrentElement(){
+        return currentElement;
+    }
+    @Override
+    public void onKeyTyped(char c, int key) {
+        textField.onKeyTyped(c, key);
+        super.onKeyTyped(c, key);
+    }
+    @Override
+    public boolean mouseClicked(Minecraft mc, int mouseX, int mouseY) {
+        boolean flag = prevButton.mouseClicked(mc, mouseX, mouseY);
+        flag |= textField.mouseClicked(mc, mouseX, mouseY);
+        flag |= nextButton.mouseClicked(mc, mouseX, mouseY);
+        super.mouseClicked(mc, mouseX, mouseY);
+        return flag;
+
+    }
+    @Override
+    public void tick()
+    {
+        prevButton.tick();
+        nextButton.tick();
+        textField.tick();
+    }
+    @Override
+    public void drawButton(Minecraft mc, int mouseX, int mouseY)
+    {
+        if (!visible) return;
+        prevButton.enabled = enabled;
+        prevButton.drawButton(mc, mouseX, mouseY);
+        nextButton.enabled = enabled;
+        nextButton.drawButton(mc, mouseX, mouseY);
+        textField.enabled = enabled;
+        textField.drawButton(mc, mouseX, mouseY);
+    }
+    @Override
+    public void onValueChanged(){
+        super.onValueChanged();
+        textField.setText(getNameFromElement(getCurrentElement()));
+    }
+    @Override
+    public void setX(int x) {
+        this.xPosition = x;
+        prevButton.setX(x);
+        nextButton.setX(x + getWidth() - nextButton.getWidth());
+        textField.setX(x + nextButton.width + 1);
+    }
+
+    @Override
+    public void setY(int y) {
+        this.yPosition = y;
+        prevButton.setY(y);
+        nextButton.setY(y);
+        textField.setY(y);
+    }
+    @Override
+    public boolean isHovered(int mouseX, int mouseY)
+    {
+        // TODO replace with a better way of allowing keypresses to be recieved while focused
+        return textField.isFocused || super.isHovered(mouseX, mouseY);
+    }
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/elements/IActionListener.java b/src/main/java/net/minecraft/client/gui/modelviewer/elements/IActionListener.java
new file mode 100644
index 000000000..2864f3488
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/elements/IActionListener.java
@@ -0,0 +1,6 @@
+package net.minecraft.client.gui.modelviewer.elements;
+
+@FunctionalInterface
+public interface IActionListener {
+    void onInteract();
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/elements/IKeyListener.java b/src/main/java/net/minecraft/client/gui/modelviewer/elements/IKeyListener.java
new file mode 100644
index 000000000..69dfafbc9
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/elements/IKeyListener.java
@@ -0,0 +1,5 @@
+package net.minecraft.client.gui.modelviewer.elements;
+@FunctionalInterface
+public interface IKeyListener {
+    void onKeyPressed(int key);
+}
diff --git a/src/main/java/net/minecraft/client/gui/modelviewer/elements/IListenerElement.java b/src/main/java/net/minecraft/client/gui/modelviewer/elements/IListenerElement.java
new file mode 100644
index 000000000..98a74d34d
--- /dev/null
+++ b/src/main/java/net/minecraft/client/gui/modelviewer/elements/IListenerElement.java
@@ -0,0 +1,9 @@
+package net.minecraft.client.gui.modelviewer.elements;
+
+public interface IListenerElement {
+    void setActionListener(IActionListener listener);
+    void setKeyListener(IKeyListener listener);
+    void setOnValueChanged(Runnable action);
+    void onKeyTyped(char c, int key);
+    void onValueChanged();
+}
diff --git a/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java b/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
index 1b75daccd..8bf33c70c 100644
--- a/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
+++ b/src/main/java/net/minecraft/client/gui/options/data/OptionsPages.java
@@ -1,13 +1,19 @@
 package net.minecraft.client.gui.options.data;
 
+import net.betterthanadventure.utils.BiomeFinder;
+import net.betterthanadventure.utils.DataDumper;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.GuiControllerSetup;
 import net.minecraft.client.gui.GuiHudDesigner;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
 import net.minecraft.client.gui.options.components.*;
+import net.minecraft.client.player.controller.PlayerControllerSP;
+import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.Utils;
+import net.minecraft.core.world.World;
 
 import java.io.File;
 
@@ -85,6 +91,7 @@ public abstract class OptionsPages
             .withComponent(new BooleanOptionComponent(mc.gameSettings.heatHaze))
         )
         .withComponent(new OptionsCategory("gui.options.page.video.category.visuals")
+            .withComponent(new ToggleableOptionComponent<>(mc.gameSettings.lightmapStyle))
             .withComponent(new BooleanOptionComponent(mc.gameSettings.fog))
             .withComponent(new BooleanOptionComponent(mc.gameSettings.biomeWater))
             .withComponent(new BooleanOptionComponent(mc.gameSettings.treeShadows))
@@ -206,6 +213,22 @@ public abstract class OptionsPages
     public static final OptionsPage SEARCH = register(new OptionsPage("gui.options.page.search.title", new ItemStack(Block.glass))
         .withComponent(new SearchFieldComponent())
     );
+    public static final OptionsPage DEBUG = new OptionsPage("gui.options.page.debug.title", Block.bedrock.getDefaultStack())
+            .withComponent(new ShortcutComponent("gui.options.page.debug.button.open.model_viewer", () -> {
+                mc.playerController = new PlayerControllerSP(mc);
+                mc.changeWorld(new World(), "Loading Model Viewer");
+                mc.displayGuiScreen(new GuiModelViewer());})
+            )
+            .withComponent(new ShortcutComponent("gui.options.page.debug.button.open.biome_finder", () -> {
+                BiomeFinder.main(new String[0]);
+                Global.accessor = mc;
+            }))
+            .withComponent(new ShortcutComponent("gui.options.page.debug.button.open.datadumper", () ->{
+                DataDumper.main(new String[0]);
+                Utils.openDirectory(new File(mc.getMinecraftDir(), "infodump"));
+                Global.accessor = mc;
+            }))
+            ;
 
     public static OptionsPage register(OptionsPage page)
     {
diff --git a/src/main/java/net/minecraft/client/option/GameSettings.java b/src/main/java/net/minecraft/client/option/GameSettings.java
index dbce20936..e88aace56 100644
--- a/src/main/java/net/minecraft/client/option/GameSettings.java
+++ b/src/main/java/net/minecraft/client/option/GameSettings.java
@@ -8,6 +8,7 @@ import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.PrintWriter;
 
+import net.minecraft.client.option.enums.*;
 import net.minecraft.client.render.tessalator.TessellatorStandard;
 import org.lwjgl.opengl.Display;
 
@@ -16,13 +17,7 @@ import com.b100.utils.ReflectUtils;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.discord.RichPresenceHandlerThread;
 import net.minecraft.client.gui.hud.HudComponents;
-import net.minecraft.client.option.enums.Colorblindness;
-import net.minecraft.client.option.enums.Difficulty;
-import net.minecraft.client.option.enums.MipmapType;
 import net.minecraft.core.enums.PlacementMode;
-import net.minecraft.client.option.enums.RenderDistance;
-import net.minecraft.client.option.enums.RenderScale;
-import net.minecraft.client.option.enums.TooltipStyle;
 import net.minecraft.client.render.window.GameWindowLWJGL2;
 import net.minecraft.core.lang.I18n;
 import net.minecraft.core.sound.SoundCategory;
@@ -155,7 +150,7 @@ public class GameSettings {
 	public BooleanOption borderlessFullscreen = new BooleanOption(this, "borderlessFullscreen", true);
 	public BooleanOption startInFullscreen = new BooleanOption(this, "startInFullscreen", true);
 	public EnumOption<TooltipStyle> tooltipStyle = new EnumOption<>(this, "tooltipStyle", TooltipStyle.class);
-	
+	public EnumOption<LightmapStyle> lightmapStyle = new EnumOption<>(this, "lightmapStyle", LightmapStyle.class, LightmapStyle.DEFAULT);
 	public BooleanOption fog = new BooleanOption(this, "fog", true);
 	public BooleanOption hideUndiscoveredItems = new BooleanOption(this, "hideUndiscoveredItems", true);
 	public BooleanOption muteOnLostFocus = new BooleanOption(this, "muteOnLostFocus", false);
@@ -320,6 +315,9 @@ public class GameSettings {
 				return trans.translateKey("options.graphics.fast");
 			}
 		}
+		if (option == lightmapStyle) {
+			return trans.translateKey(lightmapStyle.value.getTranslationKey());
+		}
 		if(option == bloom) {
 			if(bloom.value == 0) {
 				return trans.translateKey("options.off");
@@ -405,6 +403,11 @@ public class GameSettings {
 				mc.renderGlobal.loadRenderers();
 			}
 		}
+		if(option == lightmapStyle) {
+			if (mc.renderGlobal != null) {
+				mc.renderGlobal.loadRenderers();
+			}
+		}
 	}
 
 	public void loadOptions() {
diff --git a/src/main/java/net/minecraft/client/option/enums/LightmapStyle.java b/src/main/java/net/minecraft/client/option/enums/LightmapStyle.java
new file mode 100644
index 000000000..36450e11c
--- /dev/null
+++ b/src/main/java/net/minecraft/client/option/enums/LightmapStyle.java
@@ -0,0 +1,17 @@
+package net.minecraft.client.option.enums;
+
+public enum LightmapStyle {
+    DEFAULT("options.lightmapStyle.default"),
+    COSY("options.lightmapStyle.cosy"),
+    DISABLED("options.lightmapStyle.disabled");
+
+    private final String translationKey;
+
+    LightmapStyle(String translationKey) {
+        this.translationKey = translationKey;
+    }
+
+    public String getTranslationKey() {
+        return this.translationKey;
+    }
+}
diff --git a/src/main/java/net/minecraft/client/render/ChunkRenderer.java b/src/main/java/net/minecraft/client/render/ChunkRenderer.java
index e2e0a9e87..a75ad9c5b 100644
--- a/src/main/java/net/minecraft/client/render/ChunkRenderer.java
+++ b/src/main/java/net/minecraft/client/render/ChunkRenderer.java
@@ -131,6 +131,11 @@ public class ChunkRenderer
                             GL11.glTranslatef((float)sizeDepth / 2.0F, (float)sizeHeight / 2.0F, (float)sizeDepth / 2.0F);
                             tessellator.startDrawingQuads();
                             tessellator.setTranslation(-posX, -posY, -posZ);
+                            
+                            if(LightmapHelper.isLightmapEnabled()) {
+                            	// Make sure it's active
+                            	tessellator.setLightmapCoord(LightmapHelper.getLightmapCoord(15, 15));
+                            }
                         }
                         if(renderPass == 0 && Block.isEntityTile[blockId])
                         {
@@ -148,6 +153,11 @@ public class ChunkRenderer
                         }
                         else
                         {
+                        	if(LightmapHelper.isLightmapEnabled()) {
+                        		// Can probably be removed once all block models support the lightmap
+                        		tessellator.setLightmapCoord(LightmapHelper.getLightmapCoord(15, 0));	
+                        	}
+                            
                             BlockModel<Block> model = BlockModelDispatcher.getInstance().getDispatch(block);
                             hasRenderedBlock |= model.render(tessellator, x, y, z);
                             if (model.hasOverbright())
diff --git a/src/main/java/net/minecraft/client/render/FogManager.java b/src/main/java/net/minecraft/client/render/FogManager.java
index 1a6ad6266..d262f9357 100644
--- a/src/main/java/net/minecraft/client/render/FogManager.java
+++ b/src/main/java/net/minecraft/client/render/FogManager.java
@@ -9,10 +9,12 @@ import org.lwjgl.opengl.NVFogDistance;
 import net.minecraft.client.GLAllocation;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.GuiPhotoMode;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
 import net.minecraft.client.option.enums.RenderDistance;
 import net.minecraft.client.render.camera.CameraUtil;
 import net.minecraft.client.render.colorizer.ColorizerWater;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.net.packet.Packet;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.Vec3d;
 import net.minecraft.core.world.Dimension;
@@ -168,6 +170,12 @@ public class FogManager {
         fogRed *= brightness;
         fogGreen *= brightness;
         fogBlue *= brightness;
+        if (mc.currentScreen instanceof GuiModelViewer) {
+            float[] color = ((GuiModelViewer) mc.currentScreen).getBackgroundFogColor();
+            fogRed = color[0];
+            fogGreen = color[1];
+            fogBlue = color[2];
+        }
         glClearColor(fogRed, fogGreen, fogBlue, 0.0F);
     }
 
diff --git a/src/main/java/net/minecraft/client/render/LightmapHelper.java b/src/main/java/net/minecraft/client/render/LightmapHelper.java
new file mode 100644
index 000000000..6be738409
--- /dev/null
+++ b/src/main/java/net/minecraft/client/render/LightmapHelper.java
@@ -0,0 +1,272 @@
+package net.minecraft.client.render;
+
+import static org.lwjgl.opengl.GL11.*;
+import static org.lwjgl.opengl.GL13.*;
+
+import java.nio.ByteBuffer;
+
+import net.minecraft.client.GLAllocation;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.option.enums.LightmapStyle;
+import net.minecraft.core.util.helper.Buffer;
+import net.minecraft.core.util.helper.MathHelper;
+import net.minecraft.core.world.World;
+
+public class LightmapHelper {
+	private static LightmapHelper instance = null;
+
+	public static boolean isLightmapEnabled() {
+		return instance != null && instance.isEnabled();
+	}
+
+	public final Minecraft mc;
+	public final WorldRenderer worldRenderer;
+
+	private int lightmapTexture = 0;
+	private int[] lightmapData = new int[256];
+
+	public LightmapHelper(Minecraft mc, WorldRenderer worldRenderer) {
+		this.mc = mc;
+		this.worldRenderer = worldRenderer;
+		instance = this;
+	}
+
+	public boolean isEnabled() {
+		return mc.gameSettings.lightmapStyle.value != LightmapStyle.DISABLED;
+	}
+
+	public void update(float partialTicks) {
+		World world = mc.theWorld;
+
+		if(!isEnabled() || world == null) {
+			return;
+		}
+
+		if(mc.fullbright) {
+			for(int i = 0; i < lightmapData.length; i++) {
+				lightmapData[i] = 0xFFFFFFFF;
+			}
+		} else {
+			switch (mc.gameSettings.lightmapStyle.value) {
+				case DEFAULT:
+					generateGrayLightmap(world, partialTicks);
+					break;
+				case COSY:
+					generateVanillaLightmap(world, partialTicks);
+					break;
+			}
+		}
+
+		OpenGLHelper.checkError("pre generate lightmap");
+		setLightmapTextureData(lightmapData);
+		OpenGLHelper.checkError("generate lightmap");
+	}
+
+	public void disableLightmapRendering() {
+		glClientActiveTexture(GL_TEXTURE1);
+		glActiveTexture(GL_TEXTURE1);
+
+		glDisable(GL_TEXTURE_2D);
+
+		glClientActiveTexture(GL_TEXTURE0);
+		glActiveTexture(GL_TEXTURE0);
+	}
+
+	public void enableLightmapRendering() {
+		if(!isEnabled()) {
+			return;
+		}
+
+		OpenGLHelper.checkError("pre enable lightmap");
+
+		// Switch active texture
+		glClientActiveTexture(GL_TEXTURE1);
+		glActiveTexture(GL_TEXTURE1);
+
+		// Setup texture matrix
+		glMatrixMode(GL_TEXTURE);
+		glLoadIdentity();
+
+		float scale = 1.0f / 256.0f;
+		glScalef(scale, scale, scale);
+		glTranslatef(8.0f, 8.0f, 8.0f);
+
+		glMatrixMode(GL_MODELVIEW);
+
+		// Bind texture
+		mc.renderEngine.bindTexture(lightmapTexture);
+
+		// Back to default texture
+		glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+		glEnable(GL_TEXTURE_2D);
+		glClientActiveTexture(GL_TEXTURE0);
+		glActiveTexture(GL_TEXTURE0);
+
+		OpenGLHelper.checkError("enable lightmap");
+	}
+
+	public void generateGrayLightmap(World world, float partialTicks) {
+		for(int i = 0; i < 256; i++) {
+			int skyLight = i / 16;
+			int blockLight = i & 15;
+
+			skyLight = Math.max(0, skyLight - world.skyDarken);
+
+			int light = Math.max(skyLight, blockLight);
+
+			float brightness = world.worldType.getBrightnessRamp()[light];
+
+			int brightnessI = (int) (brightness * 255);
+
+			int color = 0xFF000000 | brightnessI << 16 | brightnessI << 8 | brightnessI;
+
+			lightmapData[i] = color;
+		}
+	}
+
+	public void generateVanillaLightmap(World world, float partialTicks) {
+		float ambientBrightness = world.getAmbientBrightness(partialTicks);
+		float brightness = 0.0f;
+
+		for(int i = 0; i < 256; i++) {
+			float skyLight = getBrightnessRemoveMinLight(world, i / 16) * (ambientBrightness * 0.95f + 0.05f);
+			float blockLight = getBrightnessRemoveMinLight(world, i % 16) * (0.0f * 0.1f + 1.5f);
+
+			if(world.lightningFlicker > 0) {
+				skyLight = getBrightnessRemoveMinLight(world, i / 16);
+			}
+
+			float skyRed = skyLight * (ambientBrightness * 0.65F + 0.35F);
+			float skyGreen = skyLight * (ambientBrightness * 0.65F + 0.35F);
+			float skyBlue = skyLight;
+
+			float torchRed = blockLight;
+			float torchGreen = blockLight * ((blockLight * 0.6F + 0.4F) * 0.6F + 0.4F);
+			float torchBlue = blockLight * (blockLight * blockLight * 0.6F + 0.4F);
+
+			float red = skyRed + torchRed;
+			float green = skyGreen + torchGreen;
+			float blue = skyBlue + torchBlue;
+
+			red = red * 0.96f + 0.03f;
+			green = green * 0.96f + 0.03f;
+			blue = blue * 0.96f + 0.03f;
+
+			red = MathHelper.clamp(red, 0.0f, 1.0f);
+			green = MathHelper.clamp(green, 0.0f, 1.0f);
+			blue = MathHelper.clamp(blue, 0.0f, 1.0f);
+
+			red = applyGamma(red, brightness) * 0.96f + 0.03f;
+			green = applyGamma(green, brightness) * 0.96f + 0.03f;
+			blue = applyGamma(blue, brightness) * 0.96f + 0.03f;
+
+			red = MathHelper.clamp(red, 0.0f, 1.0f);
+			green = MathHelper.clamp(green, 0.0f, 1.0f);
+			blue = MathHelper.clamp(blue, 0.0f, 1.0f);
+
+			lightmapData[i] = toIntARGB(red, green, blue);
+		}
+	}
+
+	public void setLightmapTextureData(int[] data) {
+		OpenGLHelper.checkError("pre set lightmap data");
+
+		Buffer.checkBufferSize(16 * 16 * 4);
+		ByteBuffer buffer = Buffer.buffer;
+		buffer.clear();
+
+		for(int i = 0; i < lightmapData.length; i++) {
+			int color = lightmapData[i];
+
+			int a = color >> 24;
+			int r = (color >> 16) & 0xFF;
+			int g = (color >> 8) & 0xFF;
+			int b = color & 0xFF;
+
+			buffer.put((byte) r);
+			buffer.put((byte) g);
+			buffer.put((byte) b);
+			buffer.put((byte) a);
+		}
+
+		buffer.position(0);
+		buffer.limit(16 * 16 * 4);
+
+		if(lightmapTexture == 0) {
+			lightmapTexture = GLAllocation.generateTexture();
+			glBindTexture(GL_TEXTURE_2D, lightmapTexture);
+			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ByteBuffer) null);
+		}
+
+		glBindTexture(GL_TEXTURE_2D, lightmapTexture);
+		glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 16, 16, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+		OpenGLHelper.checkError("set lightmap data");
+	}
+
+	public int toIntARGB(float red, float green, float blue) {
+		int a = 255;
+		int r = (int) (red * 255);
+		int g = (int) (green * 255);
+		int b = (int) (blue * 255);
+		return (a << 24) | (r << 16) | (g << 8) | b;
+	}
+
+	public float applyGamma(float color, float gamma) {
+		float color2 = 1.0f - color;
+		color2 = 1.0f - color2 * color2 * color2 * color2;
+		return color * (1.0f - gamma) + color2 * gamma;
+	}
+
+	public float getBrightnessRemoveMinLight(World world, int i) {
+		float brightness = world.worldType.getBrightnessRamp()[i];
+		float min = 0.05f;
+
+		return (brightness - min) / (1.0f - min);
+	}
+
+	public static int getLightmapCoord(int skylight, int blocklight) {
+		return skylight << 20 | blocklight << 4;
+	}
+	
+	public static int getOverbrightLightmapCoord(int skylight) {
+		return getLightmapCoord(skylight, 15);
+	}
+	
+	public static int max(int lightmapCoord1, int lightmapCoord2) {
+		int sky1 = lightmapCoord1 >> 16;
+		int sky2 = lightmapCoord2 >> 16;
+		
+		int block1 = lightmapCoord1 & 0xFFFF;
+		int block2 = lightmapCoord2 & 0xFFFF;
+		
+		return Math.max(sky1, sky2) << 16 | Math.max(block1, block2);
+	}
+	
+	public static int avg(int lmc0, int lmc1) {
+		int sky0 = lmc0 >> 16;
+		int sky1 = lmc1 >> 16;
+		
+		int block0 = lmc0 & 0xFFFF;
+		int block1 = lmc1 & 0xFFFF;
+		
+		int sky = (sky0 + sky1) >> 1;
+		int block = (block0 + block1) >> 1;
+		
+		return sky << 16 | block;
+	}
+	
+	public static int avg(int lmc0, int lmc1, int lmc2, int lmc3) {
+//		int lmc01 = (lmc0 + lmc1) >> 1;
+//		int lmc23 = (lmc2 + lmc3) >> 1;
+//		return (lmc01 + lmc23) >> 1;
+		return avg(avg(lmc0, lmc1), avg(lmc2, lmc3));
+	}
+
+}
diff --git a/src/main/java/net/minecraft/client/render/RenderBlockCache.java b/src/main/java/net/minecraft/client/render/RenderBlockCache.java
index dd9cc7887..abcf39cfc 100644
--- a/src/main/java/net/minecraft/client/render/RenderBlockCache.java
+++ b/src/main/java/net/minecraft/client/render/RenderBlockCache.java
@@ -9,15 +9,23 @@ import java.util.Arrays;
 
 final public class RenderBlockCache {
     private final Minecraft mc = Minecraft.getMinecraft(this);
+    
     private static final int CACHE_RANGE = 1;
     private static final int CACHE_SIZE = CACHE_RANGE*2+1;
+    
     private final boolean[] brightnessCached = new boolean[CACHE_SIZE*CACHE_SIZE*CACHE_SIZE];
     private final float[] brightnessValue = new float[CACHE_SIZE*CACHE_SIZE*CACHE_SIZE];
+    
     private final boolean[] opacityCached = new boolean[CACHE_SIZE*CACHE_SIZE*CACHE_SIZE];
     private final boolean[] opacityValue = new boolean[CACHE_SIZE*CACHE_SIZE*CACHE_SIZE];
+    
+    private final boolean[] lightmapCoordCached = new boolean[CACHE_SIZE*CACHE_SIZE*CACHE_SIZE];
+    private final int[] lightmapCoordValue = new int[CACHE_SIZE*CACHE_SIZE*CACHE_SIZE];
+    
     private int offsetX = Integer.MAX_VALUE;
     private int offsetY = Integer.MAX_VALUE;
     private int offsetZ = Integer.MAX_VALUE;
+    
     private Block block;
     private WorldSource access;
 
@@ -27,34 +35,45 @@ final public class RenderBlockCache {
             this.access = access;
             Arrays.fill(brightnessCached, false);
             Arrays.fill(opacityCached, false);
+            Arrays.fill(lightmapCoordCached, false);
             offsetX = x;
             offsetY = y;
             offsetZ = z;
         }
     }
-    public float getBrightness(int relX, int relY, int relZ) {
-        if (mc.fullbright && (access.getBlock(relX + offsetX, relY + offsetY, relZ + offsetZ) == null || !access.isBlockOpaqueCube(relX + offsetX, relY + offsetY, relZ + offsetZ))) return 1.0f;
 
-        if(mc.isTreeShadingEnabled() && mc.isAmbientOcclusionEnabled())
-        {
-            if (access.getBlock(relX + offsetX, relY + offsetY, relZ + offsetZ) instanceof BlockLeavesBase)
-            {
-                float brightness = access.getBrightness(relX + offsetX, relY + offsetY, relZ + offsetZ, Block.lightEmission[access.getBlockId(relX + offsetX, relY + offsetY, relZ + offsetZ)]);
-                if (brightness > 0.2F)
-                {
-                    brightness = 0.2F;
-                }
-                return brightness;
-            }
-        }
-
-        int index = (relX+CACHE_RANGE)*CACHE_SIZE*CACHE_SIZE+(relY+CACHE_RANGE)*CACHE_SIZE+(relZ+CACHE_RANGE);
-        if (!brightnessCached[index]) {
-            brightnessValue[index] = block.getBlockBrightness(access, relX + offsetX, relY + offsetY, relZ + offsetZ);
-            brightnessCached[index] = true;
-        }
-        return brightnessValue[index];
-    }
+	public float getBrightness(int relX, int relY, int relZ) {
+		int x1 = relX + offsetX;
+		int y1 = relY + offsetY;
+		int z1 = relZ + offsetZ;
+		
+		if(LightmapHelper.isLightmapEnabled() || mc.fullbright) {
+			Block block = access.getBlock(x1, y1, z1);
+			if(block == null) {
+				return 1.0f;
+			}
+			return 1.0f - block.getAmbientOcclusionStrength(access, x1, y1, z1);
+		}
+		
+		if(mc.isTreeShadingEnabled() && mc.isAmbientOcclusionEnabled()) {
+			if(access.getBlock(x1, y1, z1) instanceof BlockLeavesBase) {
+				float brightness = access.getBrightness(x1, y1, z1, Block.lightEmission[access.getBlockId(x1, y1, z1)]);
+				if(brightness > 0.2F) {
+					brightness = 0.2F;
+				}
+				return brightness;
+			}
+		}
+		
+		int index = (relX + CACHE_RANGE) * CACHE_SIZE * CACHE_SIZE + (relY + CACHE_RANGE) * CACHE_SIZE + (relZ + CACHE_RANGE);
+		if(!brightnessCached[index]) {
+			brightnessValue[index] = block.getBlockBrightness(access, x1, y1, z1);
+			brightnessCached[index] = true;
+		}
+		
+		return brightnessValue[index];
+	}
+	
     public boolean getOpacity(int relX, int relY, int relZ) {
         int index = (relX+CACHE_RANGE)*CACHE_SIZE*CACHE_SIZE+(relY+CACHE_RANGE)*CACHE_SIZE+(relZ+CACHE_RANGE);
         if(!opacityCached[index]){
@@ -63,4 +82,13 @@ final public class RenderBlockCache {
         }
         return opacityValue[index];
     }
+    
+    public int getLightmapCoord(int relX, int relY, int relZ) {
+    	int index = (relX + CACHE_RANGE) * CACHE_SIZE * CACHE_SIZE + (relY + CACHE_RANGE) * CACHE_SIZE + (relZ + CACHE_RANGE);
+    	if(!lightmapCoordCached[index]) {
+    		lightmapCoordValue[index] = access.getLightmapCoord(relX + offsetX, relY + offsetY, relZ + offsetZ, Block.lightEmission[block.id]);
+    		lightmapCoordCached[index] = true;
+    	}
+    	return lightmapCoordValue[index];
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/client/render/RenderBlocks.java b/src/main/java/net/minecraft/client/render/RenderBlocks.java
index e53048021..e7c35ec0c 100644
--- a/src/main/java/net/minecraft/client/render/RenderBlocks.java
+++ b/src/main/java/net/minecraft/client/render/RenderBlocks.java
@@ -219,8 +219,8 @@ public class RenderBlocks
         boolean rendered = false;
         block.setBlockBoundsBasedOnSide(this.blockAccess, x, y, z, Side.getSideById(side));
         if (this.renderAllFaces || blockModel.shouldSideBeRendered(this.blockAccess, x+dirX, y+dirY, z+dirZ, side, meta)) {
-
-            setupLighting(r, g, b, side, meta,
+        	
+            setupLighting(block, x, y, z, r, g, b, side, meta,
                     dirX, dirY, dirZ, depth,
                     topX, topY, topZ, topP, botP,
                     lefX, lefY, lefZ, lefP, rigP);
@@ -242,15 +242,70 @@ public class RenderBlocks
         }
         return rendered;
     }
-    public final void setupLighting(float r, float g, float b, int side, int meta,
+    public final void setupLighting(Block block, int x, int y, int z, float r, float g, float b, int side, int meta,
                                     int dirX, int dirY, int dirZ, float depth,
                                     int topX, int topY, int topZ, float topP, float botP,
                                     int lefX, int lefY, int lefZ, float lefP, float rigP){
+    	boolean ao = mc.isAmbientOcclusionEnabled();
+        
+    	if(LightmapHelper.isLightmapEnabled()) {
+    		int lmc;
+    		if(overbright) {
+				// TODO use correct skylight value, requires a getSavedLightValue method in WorldSource
+    			lmc = LightmapHelper.getOverbrightLightmapCoord(0);
+    		}else {
+            	if(depth > FULL_CUBE_THRESHOLD) {
+            		lmc = block.getLightmapCoord(blockAccess, x, y, z);
+            	}else {
+            		lmc = block.getLightmapCoord(blockAccess, x + dirX, y + dirY, z + dirZ);
+            	}	
+    		}
+    		lightmapCoordTopLeft = lightmapCoordBottomLeft = lightmapCoordBottomRight = lightmapCoordTopRight = lmc;
+    		if(ao) {
+    			int dirX2 = dirX;
+    			int dirY2 = dirY;
+    			int dirZ2 = dirZ;
+    			
+    			if(depth > FULL_CUBE_THRESHOLD) {
+    				dirX2 = 0;
+    				dirY2 = 0;
+    				dirZ2 = 0;
+    			}
+    			
+    			boolean topT = cache.getOpacity(dirX2 + topX, dirY2 + topY, dirZ2 + topZ);
+    			boolean botT = cache.getOpacity(dirX2 - topX, dirY2 - topY, dirZ2 - topZ);
+    			boolean lefT = cache.getOpacity(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ);
+    			boolean rigT = cache.getOpacity(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ);
+    			
+    			boolean topLefT = cache.getOpacity(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ);
+    			boolean topRigT = cache.getOpacity(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ);
+    			boolean botLefT = cache.getOpacity(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ);
+    			boolean botRigT = cache.getOpacity(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ);
+    			
+    			int lmcCen = cache.getLightmapCoord(dirX2, dirY2, dirZ2);
+    			
+    			int lmcTop = topT ? lmcCen : cache.getLightmapCoord(dirX2 + topX, dirY2 + topY, dirZ2 + topZ);
+    			int lmcBot = botT ? lmcCen : cache.getLightmapCoord(dirX2 - topX, dirY2 - topY, dirZ2 - topZ);
+    			int lmcLef = lefT ? lmcCen : cache.getLightmapCoord(dirX2 + lefX, dirY2 + lefY, dirZ2 + lefZ);
+    			int lmcRig = rigT ? lmcCen : cache.getLightmapCoord(dirX2 - lefX, dirY2 - lefY, dirZ2 - lefZ);
+
+    			int lmcTopLef = topT && lefT ? lmcLef : (topLefT ? lmcCen : cache.getLightmapCoord(dirX2 + topX + lefX, dirY2 + topY + lefY, dirZ2 + topZ + lefZ));
+    			int lmcBotLef = botT && lefT ? lmcLef : (botLefT ? lmcCen : cache.getLightmapCoord(dirX2 - topX + lefX, dirY2 - topY + lefY, dirZ2 - topZ + lefZ));
+    			int lmcTopRig = topT && rigT ? lmcRig : (topRigT ? lmcCen : cache.getLightmapCoord(dirX2 + topX - lefX, dirY2 + topY - lefY, dirZ2 + topZ - lefZ));
+    			int lmcBotRig = botT && rigT ? lmcRig : (botRigT ? lmcCen : cache.getLightmapCoord(dirX2 - topX - lefX, dirY2 - topY - lefY, dirZ2 - topZ - lefZ));
+
+    			lightmapCoordTopLeft     = LightmapHelper.avg(lmcCen, lmcLef, lmcTop, lmcTopLef);
+    			lightmapCoordTopRight    = LightmapHelper.avg(lmcCen, lmcRig, lmcTop, lmcTopRig);
+    			lightmapCoordBottomLeft  = LightmapHelper.avg(lmcCen, lmcLef, lmcBot, lmcBotLef);
+    			lightmapCoordBottomRight = LightmapHelper.avg(lmcCen, lmcRig, lmcBot, lmcBotRig);
+    		}
+    	}
+    	
         float lightTR;
         float lightBR;
         float lightBL;
         float lightTL;
-
+    	
         if (this.overbright) {
             lightTR = 1.0F;
             lightBR = 1.0F;
@@ -259,7 +314,7 @@ public class RenderBlocks
         } else if (this.field_22352_G <= 0) {
             lightTL = lightBL = lightBR = lightTR = cache.getBrightness(dirX, dirY, dirZ);
         } else {
-            if (mc.isAmbientOcclusionEnabled()) {
+            if (ao) {
                 {
                     float dirB = cache.getBrightness(dirX, dirY, dirZ);
                     boolean lefT = cache.getOpacity(dirX + lefX, dirY + lefY, dirZ + lefZ);
@@ -279,7 +334,7 @@ public class RenderBlocks
                     lightBR = (dirB + bB + rB + brB) / 4.0F;
                     lightBL = (lB + blB + dirB + bB) / 4.0F;
                 }
-                if(depth > 0.01){
+                if(depth > FULL_CUBE_THRESHOLD){
                     float dirB = cache.getBrightness(0, 0, 0);
                     boolean lefT = cache.getOpacity(lefX, lefY, lefZ);
                     boolean botT = cache.getOpacity(-topX, -topY, -topZ);
@@ -407,16 +462,21 @@ public class RenderBlocks
         double d15 = z + block.maxZ;
         if(enableAO)
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.setColorOpaque_F(colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft);
             tessellator.addVertexWithUV(d11, d13, d15, d8, d10);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomLeft);
             tessellator.setColorOpaque_F(colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft);
             tessellator.addVertexWithUV(d11, d13, d14, d3, d5);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomRight);
             tessellator.setColorOpaque_F(colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight);
             tessellator.addVertexWithUV(d12, d13, d14, d7, d9);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopRight);
             tessellator.setColorOpaque_F(colorRedTopRight, colorGreenTopRight, colorBlueTopRight);
             tessellator.addVertexWithUV(d12, d13, d15, d4, d6);
         } else
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.addVertexWithUV(d11, d13, d15, d8, d10);
             tessellator.addVertexWithUV(d11, d13, d14, d3, d5);
             tessellator.addVertexWithUV(d12, d13, d14, d7, d9);
@@ -490,16 +550,21 @@ public class RenderBlocks
         double d15 = z + block.maxZ;
         if(enableAO)
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.setColorOpaque_F(colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft);
             tessellator.addVertexWithUV(d12, d13, d15, d4, d6);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomLeft);
             tessellator.setColorOpaque_F(colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft);
             tessellator.addVertexWithUV(d12, d13, d14, d7, d9);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomRight);
             tessellator.setColorOpaque_F(colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight);
             tessellator.addVertexWithUV(d11, d13, d14, d3, d5);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopRight);
             tessellator.setColorOpaque_F(colorRedTopRight, colorGreenTopRight, colorBlueTopRight);
             tessellator.addVertexWithUV(d11, d13, d15, d8, d10);
         } else
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.addVertexWithUV(d12, d13, d15, d4, d6);
             tessellator.addVertexWithUV(d12, d13, d14, d7, d9);
             tessellator.addVertexWithUV(d11, d13, d14, d3, d5);
@@ -579,16 +644,21 @@ public class RenderBlocks
         double d16 = z + block.minZ;
         if(enableAO)
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.setColorOpaque_F(colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft);
             tessellator.addVertexWithUV(d12, d15, d16, d8, d10);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomLeft);
             tessellator.setColorOpaque_F(colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft);
             tessellator.addVertexWithUV(d13, d15, d16, d3, d5);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomRight);
             tessellator.setColorOpaque_F(colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight);
             tessellator.addVertexWithUV(d13, d14, d16, d9, d11);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopRight);
             tessellator.setColorOpaque_F(colorRedTopRight, colorGreenTopRight, colorBlueTopRight);
             tessellator.addVertexWithUV(d12, d14, d16, d4, d6);
         } else
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.addVertexWithUV(d12, d15, d16, d8, d10);
             tessellator.addVertexWithUV(d13, d15, d16, d3, d5);
             tessellator.addVertexWithUV(d13, d14, d16, d9, d11);
@@ -661,27 +731,32 @@ public class RenderBlocks
             d10 = d5;
             d11 = d6;
         }
-        double d12 = x + block.minX;
-        double d13 = x + block.maxX;
-        double d14 = y + block.minY;
-        double d15 = y + block.maxY;
-        double d16 = z + block.maxZ;
+        double x0 = x + block.minX;
+        double x1 = x + block.maxX;
+        double y0 = y + block.minY;
+        double y1 = y + block.maxY;
+        double z0 = z + block.maxZ;
         if(enableAO)
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.setColorOpaque_F(colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft);
-            tessellator.addVertexWithUV(d12, d15, d16, d3, d5);
+            tessellator.addVertexWithUV(x0, y1, z0, d3, d5);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomLeft);
             tessellator.setColorOpaque_F(colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft);
-            tessellator.addVertexWithUV(d12, d14, d16, d9, d11);
+            tessellator.addVertexWithUV(x0, y0, z0, d9, d11);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomRight);
             tessellator.setColorOpaque_F(colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight);
-            tessellator.addVertexWithUV(d13, d14, d16, d4, d6);
+            tessellator.addVertexWithUV(x1, y0, z0, d4, d6);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopRight);
             tessellator.setColorOpaque_F(colorRedTopRight, colorGreenTopRight, colorBlueTopRight);
-            tessellator.addVertexWithUV(d13, d15, d16, d8, d10);
+            tessellator.addVertexWithUV(x1, y1, z0, d8, d10);
         } else
         {
-            tessellator.addVertexWithUV(d12, d15, d16, d3, d5);
-            tessellator.addVertexWithUV(d12, d14, d16, d9, d11);
-            tessellator.addVertexWithUV(d13, d14, d16, d4, d6);
-            tessellator.addVertexWithUV(d13, d15, d16, d8, d10);
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
+            tessellator.addVertexWithUV(x0, y1, z0, d3, d5);
+            tessellator.addVertexWithUV(x0, y0, z0, d9, d11);
+            tessellator.addVertexWithUV(x1, y0, z0, d4, d6);
+            tessellator.addVertexWithUV(x1, y1, z0, d8, d10);
         }
     }
 
@@ -759,16 +834,21 @@ public class RenderBlocks
         double d16 = z + block.maxZ;
         if(enableAO)
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.setColorOpaque_F(colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft);
             tessellator.addVertexWithUV(d12, d14, d16, d8, d10);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomLeft);
             tessellator.setColorOpaque_F(colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft);
             tessellator.addVertexWithUV(d12, d14, d15, d3, d5);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomRight);
             tessellator.setColorOpaque_F(colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight);
             tessellator.addVertexWithUV(d12, d13, d15, d9, d11);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopRight);
             tessellator.setColorOpaque_F(colorRedTopRight, colorGreenTopRight, colorBlueTopRight);
             tessellator.addVertexWithUV(d12, d13, d16, d4, d6);
         } else
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.addVertexWithUV(d12, d14, d16, d8, d10);
             tessellator.addVertexWithUV(d12, d14, d15, d3, d5);
             tessellator.addVertexWithUV(d12, d13, d15, d9, d11);
@@ -849,16 +929,21 @@ public class RenderBlocks
 
         if(enableAO)
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.setColorOpaque_F(colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft);
             tessellator.addVertexWithUV(xMax, yMin, zMax, uMin2, vMax2);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomLeft);
             tessellator.setColorOpaque_F(colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft);
             tessellator.addVertexWithUV(xMax, yMin, zMin, uMax, vMax);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordBottomRight);
             tessellator.setColorOpaque_F(colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight);
             tessellator.addVertexWithUV(xMax, yMax, zMin, uMax2, vMin2);
+            if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopRight);
             tessellator.setColorOpaque_F(colorRedTopRight, colorGreenTopRight, colorBlueTopRight);
             tessellator.addVertexWithUV(xMax, yMax, zMax, uMin, vMin);
         } else
         {
+        	if(LightmapHelper.isLightmapEnabled()) tessellator.setLightmapCoord(lightmapCoordTopLeft);
             tessellator.addVertexWithUV(xMax, yMin, zMax, uMin2, vMax2);
             tessellator.addVertexWithUV(xMax, yMin, zMin, uMax, vMax);
             tessellator.addVertexWithUV(xMax, yMax, zMin, uMax2, vMin2);
@@ -897,6 +982,7 @@ public class RenderBlocks
     public static boolean fancyGrass = true;
 
     public static final float[] SIDE_LIGHT_MULTIPLIER = {0.5f, 1.0f, 0.8f, 0.8f, 0.6f, 0.6f};
+    public static final float FULL_CUBE_THRESHOLD = 1.0f / 16.0f;
     public boolean useInventoryTint;
     public int uvRotateEast;
     public int uvRotateWest;
@@ -918,6 +1004,10 @@ public class RenderBlocks
     public float colorBlueBottomLeft;
     public float colorBlueBottomRight;
     public float colorBlueTopRight;
+    public int lightmapCoordTopLeft;
+    public int lightmapCoordBottomLeft;
+    public int lightmapCoordBottomRight;
+    public int lightmapCoordTopRight; 
     public boolean overbright;
     public RenderBlockCache cache = new RenderBlockCache();
 
diff --git a/src/main/java/net/minecraft/client/render/RenderGlobal.java b/src/main/java/net/minecraft/client/render/RenderGlobal.java
index b3d254975..0d21ec3bf 100644
--- a/src/main/java/net/minecraft/client/render/RenderGlobal.java
+++ b/src/main/java/net/minecraft/client/render/RenderGlobal.java
@@ -1,5 +1,16 @@
 package net.minecraft.client.render;
 
+import java.nio.IntBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
+import org.lwjgl.opengl.ARBOcclusionQuery;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL15;
+
 import net.minecraft.client.GLAllocation;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.entity.fx.EntityArrowGoldenFX;
@@ -845,7 +856,7 @@ public class RenderGlobal
 
     public void drawSky(float partialTick)
     {
-        if(mc.theWorld.dimension == Dimension.nether)
+        if(mc.theWorld.dimension == Dimension.nether || mc.currentScreen instanceof GuiModelViewer)
         {
             return;
         }
@@ -1309,7 +1320,7 @@ public class RenderGlobal
 
     public void drawSelectionBox(ICamera camera, HitResult hitResult, float partialTick)
     {
-        if (mc.gameSettings.immersiveMode.drawOutline() && mc.gameSettings.blockOutlineWidth.value > 0.01f)
+        if (mc.gameSettings.immersiveMode.drawOutline() && mc.gameSettings.blockOutlineWidth.value > 0.01f && !(mc.currentScreen instanceof GuiModelViewer))
         {
             GL11.glEnable(3042 /*GL_BLEND*/);
             GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
@@ -1640,7 +1651,7 @@ public class RenderGlobal
         }
         if(particleId.equals("bubble"))
         {
-            mc.effectRenderer.addEffect(new EntityBubbleFX(worldObj, x, y, z, motionX, motionY, motionZ));
+            mc.effectRenderer.addEffect(new EntityBubbleFX(worldObj, x, y, z, motionX, motionY, motionZ, true));
         }
         else if(particleId.equals("smoke"))
         {
@@ -1749,6 +1760,9 @@ public class RenderGlobal
     @Override
     public void allChanged()
     {
+    	if(LightmapHelper.isLightmapEnabled()) {
+    		return;
+    	}
         for (ChunkRenderer chunkRenderer : chunkRenderers)
         {
             if (chunkRenderer.isChunkLit && !chunkRenderer.needsUpdate)
diff --git a/src/main/java/net/minecraft/client/render/WorldRenderer.java b/src/main/java/net/minecraft/client/render/WorldRenderer.java
index 3af796da9..52c76cafb 100644
--- a/src/main/java/net/minecraft/client/render/WorldRenderer.java
+++ b/src/main/java/net/minecraft/client/render/WorldRenderer.java
@@ -2,21 +2,30 @@ package net.minecraft.client.render;
 
 import java.util.List;
 import java.util.Random;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.entity.player.EntityPlayerSP;
-import net.minecraft.client.render.camera.CameraUtil;
-import net.minecraft.client.render.camera.EntityCamera;
-import net.minecraft.client.render.camera.*;
-import net.minecraft.client.render.culling.Frustum;
-import net.minecraft.client.render.tessalator.TessellatorStandard;
-import net.minecraft.client.render.stitcher.TextureRegistry;
+
 import org.lwjgl.input.Mouse;
 import org.lwjgl.opengl.GL11;
 import org.lwjgl.util.glu.GLU;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.fx.EntityRainFX;
+import net.minecraft.client.entity.fx.EntitySmokeFX;
+import net.minecraft.client.entity.player.EntityPlayerSP;
 import net.minecraft.client.gui.GuiPhotoMode;
+import net.minecraft.client.gui.modelviewer.GuiModelViewer;
 import net.minecraft.client.input.InputType;
 import net.minecraft.client.input.MouseFilter;
 import net.minecraft.client.input.PlayerInput;
+import net.minecraft.client.render.camera.CameraUtil;
+import net.minecraft.client.render.camera.EntityCamera;
+import net.minecraft.client.render.camera.EntityCameraFirstPerson;
+import net.minecraft.client.render.camera.EntityCameraIsometric;
+import net.minecraft.client.render.camera.EntityCameraSleeping;
+import net.minecraft.client.render.camera.EntityCameraThirdPersonFront;
+import net.minecraft.client.render.camera.EntityCameraThirdPersonRear;
+import net.minecraft.client.render.culling.Frustum;
+import net.minecraft.client.render.stitcher.TextureRegistry;
+import net.minecraft.client.render.tessalator.TessellatorStandard;
 import net.minecraft.client.render.window.GameWindowLWJGL2;
 import net.minecraft.client.util.debug.Debug;
 import net.minecraft.client.world.chunk.provider.ChunkProviderStatic;
@@ -25,8 +34,6 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.entity.Entity;
 import net.minecraft.core.entity.EntityLiving;
-import net.minecraft.client.entity.fx.EntityRainFX;
-import net.minecraft.client.entity.fx.EntitySmokeFX;
 import net.minecraft.core.entity.player.EntityPlayer;
 import net.minecraft.core.sound.SoundCategory;
 import net.minecraft.core.util.helper.MathHelper;
@@ -41,9 +48,12 @@ import net.minecraft.core.world.weather.Weather;
 public class WorldRenderer
 {
     public static final long nsPerSecond = 1_000_000_000L;
+    public final LightmapHelper lightmapHelper;
 
     public WorldRenderer(Minecraft minecraft)
     {
+    	this.mc = minecraft;
+    	this.lightmapHelper = new LightmapHelper(minecraft, this);
         farPlaneDistance = 0.0F;
         pointedEntity = null;
         mouseFilterXAxis = new MouseFilter();
@@ -71,7 +81,6 @@ public class WorldRenderer
         rainSoundCounter = 0;
         field_1394_b = 0;
         field_1393_c = 0;
-        mc = minecraft;
         itemRenderer = new ItemRenderer(minecraft);
         fogManager = new FogManager(mc);
     }
@@ -410,6 +419,8 @@ public class WorldRenderer
         }
         return minFOV + 2 * (currentFov - minFOV) * logisticFunc(_zoom);
     }
+    
+    
     private float logisticFunc(float val){
         final float L = 1;
         final float k = 1.1f;
@@ -419,6 +430,7 @@ public class WorldRenderer
 
     public void updateCameraAndRender(float partialTick)
     {
+    	lightmapHelper.update(partialTick);
         if(mc.inGameHasFocus)
         {
 			if(Mouse.isGrabbed()) {
@@ -622,7 +634,7 @@ public class WorldRenderer
         setupCameraTransform(partialTick);
         Frustum.getFrustum();
         Debug.change("sky");
-        if(mc.gameSettings.renderDistance.value.renderSky)
+        if(mc.gameSettings.renderDistance.value.renderSky && !(mc.currentScreen instanceof GuiModelViewer))
         {
             fogManager.setupFog(FogManager.FOG_MODE_SKY, farPlaneDistance, partialTick);
             GL11.glDisable(GL11.GL_FOG);
@@ -663,7 +675,9 @@ public class WorldRenderer
         Lighting.disable();
 
         Debug.change("terrain");
+        lightmapHelper.enableLightmapRendering();
         renderGlobal.sortAndRender(mc.activeCamera, 0, partialTick);
+        lightmapHelper.disableLightmapRendering();
 
         Debug.change("entities");
         GL11.glShadeModel(7424 /*GL_FLAT*/);
@@ -720,6 +734,7 @@ public class WorldRenderer
             GL11.glColorMask(true, true, true, true);
             if(i1 > 0)
             {
+                lightmapHelper.enableLightmapRendering();
                 if (!mc.gameSettings.fog.value)
                 {
                     GL11.glDisable(GL11.GL_FOG);
@@ -729,12 +744,15 @@ public class WorldRenderer
                 {
                     GL11.glEnable(GL11.GL_FOG);
                 }
+                lightmapHelper.disableLightmapRendering();
             }
             GL11.glShadeModel(GL11.GL_FLAT);
         }
         else
         {
+        	lightmapHelper.enableLightmapRendering();
             renderGlobal.sortAndRender(mc.activeCamera, 1, partialTick);
+            lightmapHelper.disableLightmapRendering();
         }
         
         Debug.change("weather");
@@ -758,7 +776,7 @@ public class WorldRenderer
             setupPlayerCamera(partialTick);
         }
 
-        GL11.glColorMask(true, true, true, false);
+        GL11.glColorMask(true, true, true, true);
         Debug.pop();
     }
 
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelAlgae.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelAlgae.java
index 8b5ecff40..c8bccb950 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelAlgae.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelAlgae.java
@@ -1,5 +1,6 @@
 package net.minecraft.client.render.block.model;
 
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.tessalator.Tessellator;
 import net.minecraft.client.render.stitcher.IconCoordinate;
@@ -15,7 +16,12 @@ public class BlockModelAlgae<T extends Block> extends BlockModelStandard<T>{
     @Override
     public boolean render(Tessellator tessellator, int x, int y, int z) {
         block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
-        float brightness = Math.min(getBlockBrightness(renderBlocks.blockAccess, x, y - 1, z), getBlockBrightness(renderBlocks.blockAccess, x, y, z));
+        float brightness = 1.0f;
+        if(!LightmapHelper.isLightmapEnabled()) {
+        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        }else {
+        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        }
 
         int color = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(renderBlocks.blockAccess, x, y, z);
         float red = (float)(color >> 16 & 0xff) / 255F;
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsPumpkin.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsPumpkin.java
index 71d700e1b..63c4ccf27 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsPumpkin.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsPumpkin.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.stitcher.IconCoordinate;
 import net.minecraft.client.render.stitcher.TextureRegistry;
 import net.minecraft.core.block.Block;
@@ -30,7 +31,12 @@ public class BlockModelCropsPumpkin<T extends Block> extends BlockModelStandard<
     public boolean render(Tessellator tessellator, int x, int y, int z) {
         block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
 
-        final float brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        float brightness = 1.0f;
+        if(LightmapHelper.isLightmapEnabled()) {
+        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        }else {
+        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        }
         tessellator.setColorOpaque_F(brightness, brightness, brightness);
 
         final int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsWheat.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsWheat.java
index 98702a48c..b9d899708 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsWheat.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelCropsWheat.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.stitcher.IconCoordinate;
 import net.minecraft.client.render.stitcher.TextureRegistry;
 import net.minecraft.core.block.Block;
@@ -26,7 +27,12 @@ public class BlockModelCropsWheat<T extends Block> extends BlockModelStandard<T>
     @Override
     public boolean render(Tessellator tessellator, int x, int y, int z) {
         block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
-        float brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        float brightness = 1.0f;
+        if(LightmapHelper.isLightmapEnabled()) {
+        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        }else {
+        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        }
         tessellator.setColorOpaque_F(brightness, brightness, brightness);
 
         IconCoordinate texture = getBlockTextureFromSideAndMetadata(Side.BOTTOM, renderBlocks.blockAccess.getBlockMetadata(x, y, z));
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelCrossedSquares.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelCrossedSquares.java
index 0ae77411c..9f2e13215 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelCrossedSquares.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelCrossedSquares.java
@@ -1,5 +1,6 @@
 package net.minecraft.client.render.block.model;
 
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.tessalator.Tessellator;
 import net.minecraft.client.render.stitcher.IconCoordinate;
@@ -76,8 +77,14 @@ public class BlockModelCrossedSquares<T extends Block> extends BlockModelStandar
     @Override
     public boolean render(Tessellator tessellator, int x, int y, int z) {
         block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
-
-        float brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        
+        float brightness = 1.0f;
+        if(!LightmapHelper.isLightmapEnabled()) {
+        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        }else {
+        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        }
+        
         int color = BlockColorDispatcher.getInstance().getDispatch(block).getWorldColor(renderBlocks.blockAccess, x, y, z);
         float r = (float)(color >> 16 & 0xff) / 255F;
         float g = (float)(color >> 8 & 0xff) / 255F;
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
index 9448bae27..dad6f9dc5 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelDispatcher.java
@@ -383,6 +383,7 @@ public class BlockModelDispatcher
         addDispatch(new BlockModelPortal<>(Block.portalParadise).withTextures("minecraft:block/portal_nether"));
 
         addDispatch(new BlockModelCake<>(Block.cake).withTextures("minecraft:block/cake_top", "minecraft:block/cake_bottom", "minecraft:block/cake_side"));
+        addDispatch(new BlockModelPumpkinPie<>(Block.pumpkinPie).withTextures("minecraft:block/pumpkin_pie_top", "minecraft:block/pumpkin_pie_bottom", "minecraft:block/pumpkin_pie_side"));
 
         addDispatch(new BlockModelLamp<>(Block.lampIdle));
         addDispatch(new BlockModelLamp<>(Block.lampActive));
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelDoor.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelDoor.java
index ae120f600..092f5f9d9 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelDoor.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelDoor.java
@@ -1,7 +1,9 @@
 package net.minecraft.client.render.block.model;
 
-import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
+import net.minecraft.client.render.RenderBlocks;
 import net.minecraft.client.render.stitcher.IconCoordinate;
+import net.minecraft.client.render.tessalator.Tessellator;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockDoor;
 import net.minecraft.core.util.helper.Side;
@@ -10,102 +12,94 @@ public class BlockModelDoor<T extends BlockDoor> extends BlockModelStandard<T>{
     public BlockModelDoor(Block block) {
         super(block);
     }
-
-    @Override
-    public boolean render(Tessellator tessellator, int x, int y, int z) {
-        block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
-        float f = 0.5F;
-        float f1 = 1.0F;
-        float f2 = 0.8F;
-        float f3 = 0.6F;
-        float f4 = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
-        float f5 = getBlockBrightness(renderBlocks.blockAccess, x, y - 1, z);
-        boolean aboveIsDoor = renderBlocks.blockAccess.getBlock(x, y + 1, z) instanceof BlockDoor;
-        boolean belowIsDoor = renderBlocks.blockAccess.getBlock(x, y - 1, z) instanceof BlockDoor;
-        int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
-        if(block.minY > 0.0D)
-        {
-            f5 = f4;
-        }
-        if(Block.lightEmission[block.id] > 0)
-        {
-            f5 = 1.0F;
-        }
-        tessellator.setColorOpaque_F(f * f5, f * f5, f * f5);
-        if (!belowIsDoor){
-            renderBottomFace(tessellator, block, x, y, z, getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.BOTTOM));
-        }
-        f5 = getBlockBrightness(renderBlocks.blockAccess, x, y + 1, z);
-        if(block.maxY < 1.0D)
-        {
-            f5 = f4;
-        }
-        if(Block.lightEmission[block.id] > 0)
-        {
-            f5 = 1.0F;
-        }
-        tessellator.setColorOpaque_F(f1 * f5, f1 * f5, f1 * f5);
-        if (!aboveIsDoor){
-            renderTopFace(tessellator, block, x, y, z, getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.TOP));
-        }
-        f5 = getBlockBrightness(renderBlocks.blockAccess, x, y, z - 1);
-        if(block.minZ > 0.0D)
-        {
-            f5 = f4;
-        }
-        if(Block.lightEmission[block.id] > 0)
-        {
-            f5 = 1.0F;
-        }
-        tessellator.setColorOpaque_F(f2 * f5, f2 * f5, f2 * f5);
-        renderBlocks.flipTexture = shouldFlipTexture(Side.NORTH, meta);
-        IconCoordinate texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.NORTH);
-        renderNorthFace(tessellator, block, x, y, z, texture);
-        renderBlocks.flipTexture = false;
-        f5 = getBlockBrightness(renderBlocks.blockAccess, x, y, z + 1);
-        if(block.maxZ < 1.0D)
-        {
-            f5 = f4;
-        }
-        if(Block.lightEmission[block.id] > 0)
-        {
-            f5 = 1.0F;
-        }
-        tessellator.setColorOpaque_F(f2 * f5, f2 * f5, f2 * f5);
-        renderBlocks.flipTexture = shouldFlipTexture(Side.SOUTH, meta);
-        texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.SOUTH);
-        renderSouthFace(tessellator, block, x, y, z, texture);
-        renderBlocks.flipTexture = false;
-        f5 = getBlockBrightness(renderBlocks.blockAccess, x - 1, y, z);
-        if(block.minX > 0.0D)
-        {
-            f5 = f4;
-        }
-        if(Block.lightEmission[block.id] > 0)
-        {
-            f5 = 1.0F;
-        }
-        tessellator.setColorOpaque_F(f3 * f5, f3 * f5, f3 * f5);
-        renderBlocks.flipTexture = shouldFlipTexture(Side.WEST, meta);
-        texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.WEST);
-        renderWestFace(tessellator, block, x, y, z, texture);
-        renderBlocks.flipTexture = false;
-        f5 = getBlockBrightness(renderBlocks.blockAccess, x + 1, y, z);
-        if(block.maxX < 1.0D)
-        {
-            f5 = f4;
-        }
-        if(Block.lightEmission[block.id] > 0)
-        {
-            f5 = 1.0F;
-        }
-        tessellator.setColorOpaque_F(f3 * f5, f3 * f5, f3 * f5);
-        renderBlocks.flipTexture = shouldFlipTexture(Side.EAST, meta);
-        texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.EAST);
-        renderEastFace(tessellator, block, x, y, z, texture);
-        renderBlocks.flipTexture = false;
-        return true;
+    
+    public void setBrightness(Tessellator tessellator, int x, int y, int z, float sideBrightness) {
+    	float brightness = sideBrightness;
+    	if(LightmapHelper.isLightmapEnabled()) {
+    		tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+    	}else {
+    		brightness *= renderBlocks.getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+    	}
+    	tessellator.setColorOpaque_F(brightness, brightness, brightness);
     }
+    
+    @Override
+	public boolean render(Tessellator tessellator, int x, int y, int z) {
+    	if(LightmapHelper.isLightmapEnabled()) {
+    		tessellator.setLightmapCoord(LightmapHelper.getLightmapCoord(15, 15));
+    	}
+    	tessellator.setColorOpaque_F(1.0f, 1.0f, 1.0f);
+    	
+		block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
+
+		float sideBottom = 0.5f;
+		float sideTop = 1.0f;
+		float sideNorthSouth = 0.8f;
+		float sideEastWest = 0.6f;
+		
+		boolean aboveIsDoor = renderBlocks.blockAccess.getBlock(x, y + 1, z) instanceof BlockDoor;
+		boolean belowIsDoor = renderBlocks.blockAccess.getBlock(x, y - 1, z) instanceof BlockDoor;
+
+		int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+		
+		// Bottom
+		if(!belowIsDoor) {
+			setBrightness(tessellator, x, y - 1, z, sideBottom);
+			renderBottomFace(tessellator, block, x, y, z, getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.BOTTOM));
+		}
+		
+		// Top
+		if(!aboveIsDoor) {
+			setBrightness(tessellator, x, y + 1, z, sideTop);
+			renderTopFace(tessellator, block, x, y, z, getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.TOP));
+		}
+		
+		// North
+		if(block.minZ > RenderBlocks.FULL_CUBE_THRESHOLD) {
+			setBrightness(tessellator, x, y, z, sideNorthSouth);
+		}else {
+			setBrightness(tessellator, x, y, z - 1, sideNorthSouth);
+		}
+		renderBlocks.flipTexture = shouldFlipTexture(Side.NORTH, meta);
+		IconCoordinate texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.NORTH);
+		renderNorthFace(tessellator, block, x, y, z, texture);
+		renderBlocks.flipTexture = false;
+		
+		// South
+		if(block.maxZ < 1.0f - RenderBlocks.FULL_CUBE_THRESHOLD) {
+			setBrightness(tessellator, x, y, z, sideNorthSouth);
+		}else {
+			setBrightness(tessellator, x, y, z + 1, sideNorthSouth);
+		}
+		renderBlocks.flipTexture = shouldFlipTexture(Side.SOUTH, meta);
+		texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.SOUTH);
+		renderSouthFace(tessellator, block, x, y, z, texture);
+		renderBlocks.flipTexture = false;
+		
+		// West
+		if(block.minX > RenderBlocks.FULL_CUBE_THRESHOLD) {
+			setBrightness(tessellator, x, y, z, sideEastWest);
+		}else {
+			setBrightness(tessellator, x - 1, y, z, sideEastWest);
+		}
+		renderBlocks.flipTexture = shouldFlipTexture(Side.WEST, meta);
+		texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.WEST);
+		renderWestFace(tessellator, block, x, y, z, texture);
+		renderBlocks.flipTexture = false;
+		
+		// East
+		if(block.maxX < 1.0f - RenderBlocks.FULL_CUBE_THRESHOLD) {
+			setBrightness(tessellator, x, y, z, sideEastWest);
+		}else {
+			setBrightness(tessellator, x + 1, y, z, sideEastWest);
+		}
+		renderBlocks.flipTexture = shouldFlipTexture(Side.EAST, meta);
+		texture = getBlockTexture(renderBlocks.blockAccess, x, y, z, Side.EAST);
+		renderEastFace(tessellator, block, x, y, z, texture);
+		renderBlocks.flipTexture = false;
+		return true;
+	}
+    
     @Override
     public boolean shouldItemRender3d() {
         return false;
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java
index 368e5aa3d..a99bbb4f8 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelFenceThin.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
@@ -24,7 +25,13 @@ public class BlockModelFenceThin<T extends BlockFenceThin> extends BlockModelSta
     @Override
     public boolean render(Tessellator t, int x, int y, int z) {
         block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
-        float brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        float brightness = 1.0f;
+        if(LightmapHelper.isLightmapEnabled()) {
+        	t.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        }else {
+        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        }
+        t.setColorOpaque_F(brightness, brightness, brightness);
 
         float cBottom = 0.5F;
         float cTop = 1.0F;
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java
index 1130c10e5..793688b95 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelFluid.java
@@ -1,5 +1,6 @@
 package net.minecraft.client.render.block.model;
 
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.block.color.BlockColorDispatcher;
 import net.minecraft.client.render.tessalator.Tessellator;
 import net.minecraft.client.render.stitcher.IconCoordinate;
@@ -34,10 +35,12 @@ public class BlockModelFluid<T extends Block> extends BlockModelStandard<T> {
             return false;
         }
         boolean didRender = false;
-        float f3 = 0.5F;
-        final float brightness = 1.0F;
-        float f5 = 0.8F;
-        float f6 = 0.6F;
+        
+        final float sideBottom = 0.5f;
+        final float sideTop = 1.0f;
+        final float sideNorthSouth = 0.8f;
+        final float sideEastWest = 0.6f;
+        
         double d = 0.0D;
         double d1 = 1.0D;
         final float yOff = 0.001f;
@@ -58,10 +61,15 @@ public class BlockModelFluid<T extends Block> extends BlockModelStandard<T> {
             } else {
                 rotation = 0.0F;
             }
-//            if (MathHelper.PI < rotation && rotation < (MathHelper.PI/2) * 3){
-//                rotation -= MathHelper.PI/2;
-//            }
-            float blockBrightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            float blockBrightness = 1.0f;
+            if(LightmapHelper.isLightmapEnabled()) {
+            	int light = block.getLightmapCoord(renderBlocks.blockAccess, x, y, z);
+            	int lightUp = block.getLightmapCoord(renderBlocks.blockAccess, x, y + 1, z);
+            	
+            	tessellator.setLightmapCoord(LightmapHelper.max(light, lightUp));
+            }else {
+            	blockBrightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            }
             if (texture.namespaceId.contains("_flowing")){
                 double centerU = texture.getSubIconU(0.5);
                 double centerV = texture.getSubIconV(0.5);
@@ -71,13 +79,13 @@ public class BlockModelFluid<T extends Block> extends BlockModelStandard<T> {
                 double maxU = texture.getIconUMax();
                 double minV = texture.getIconVMin();
                 double maxV = texture.getIconVMax();
-                tessellator.setColorOpaque_F(brightness * blockBrightness * r, brightness * blockBrightness * g, brightness * blockBrightness * b);
+                tessellator.setColorOpaque_F(sideTop * blockBrightness * r, sideTop * blockBrightness * g, sideTop * blockBrightness * b);
                 tessellator.addVertexWithUV(x,      (float)y + f7,      z,      ((minU - centerU) * sin - (maxV - centerV) * cSin) + centerU, ((maxV - centerV) * sin + (minU - centerU) * cSin) + centerV);
                 tessellator.addVertexWithUV(x,      (float)y + f8,      z + 1,  ((maxU - centerU) * sin - (maxV - centerV) * cSin) + centerU, ((maxV - centerV) * sin + (maxU - centerU) * cSin) + centerV);
                 tessellator.addVertexWithUV(x + 1,  (float)y + f9,      z + 1,  ((maxU - centerU) * sin - (minV - centerV) * cSin) + centerU, ((minV - centerV) * sin + (maxU - centerU) * cSin) + centerV);
                 tessellator.addVertexWithUV(x + 1,  (float)y + f10,     z,      ((minU - centerU) * sin - (minV - centerV) * cSin) + centerU, ((minV - centerV) * sin + (minU - centerU) * cSin) + centerV);
             } else {
-                tessellator.setColorOpaque_F(brightness * blockBrightness * r, brightness * blockBrightness * g, brightness * blockBrightness * b);
+                tessellator.setColorOpaque_F(sideTop * blockBrightness * r, sideTop * blockBrightness * g, sideTop * blockBrightness * b);
                 tessellator.addVertexWithUV(x,      (float)y + f7,      z,      texture.getIconUMin(), texture.getIconVMax());
                 tessellator.addVertexWithUV(x,      (float)y + f8,      z + 1,  texture.getIconUMax(), texture.getIconVMax());
                 tessellator.addVertexWithUV(x + 1,  (float)y + f9,      z + 1,  texture.getIconUMax(), texture.getIconVMin());
@@ -87,8 +95,13 @@ public class BlockModelFluid<T extends Block> extends BlockModelStandard<T> {
         }
         if(renderBlocks.renderAllFaces || flag1)
         {
-            float f11 = getBlockBrightness(renderBlocks.blockAccess, x, y - 1, z);
-            tessellator.setColorOpaque_F(f3 * f11 * r, f3 * f11 * g, f3 * f11 * b);
+            float brightness = 1.0f;
+            if(LightmapHelper.isLightmapEnabled()) {
+            	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y - 1, z));
+            }else {
+            	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y - 1, z);
+            }
+            tessellator.setColorOpaque_F(sideBottom * brightness * r, sideBottom * brightness * g, sideBottom * brightness * b);
 
             renderBlocks.renderBottomFace(tessellator, block,x, y + yOff, z, getBlockTextureFromSideAndMetadata(Side.TOP, 0));
             didRender = true;
@@ -173,15 +186,18 @@ public class BlockModelFluid<T extends Block> extends BlockModelStandard<T> {
             double d6 = texture.getSubIconV(0.5F - f13/2 + vOff);
             double d7 = texture.getSubIconV(0.5F - f15/2 + vOff);
             double d8 = texture.getSubIconV(0.5F + vOff);
-            float f22 = getBlockBrightness(renderBlocks.blockAccess, xB, yB, zB);
-            if(side < 2)
-            {
-                f22 *= f5;
-            } else
-            {
-                f22 *= f6;
-            }
-            tessellator.setColorOpaque_F(brightness * f22 * r, brightness * f22 * g, brightness * f22 * b);
+			float brightness = 1.0f;
+			if(LightmapHelper.isLightmapEnabled()) {
+				tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, xB, yB, zB));
+			}else {
+				brightness = getBlockBrightness(renderBlocks.blockAccess, xB, yB, zB);
+			}
+			if(side < 2) {
+				brightness *= sideNorthSouth;
+			}else {
+				brightness *= sideEastWest;
+			}
+            tessellator.setColorOpaque_F(sideTop * brightness * r, sideTop * brightness * g, sideTop * brightness * b);
             tessellator.addVertexWithUV(f17, (float)y + f13, f19, d4, d6);
             tessellator.addVertexWithUV(f20, (float)y + f15, f21, d5, d7);
             tessellator.addVertexWithUV(f20, y, f21, d5, d8);
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelLadder.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelLadder.java
index db427f2a5..199e36389 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelLadder.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelLadder.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.util.helper.Side;
@@ -19,8 +20,13 @@ public class BlockModelLadder<T extends Block> extends BlockModelStandard<T> {
         {
             l = renderBlocks.overrideBlockTexture;
         }
-        float f = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
-        tessellator.setColorOpaque_F(f, f, f);
+        float brightness = 1.0f;
+        if(!LightmapHelper.isLightmapEnabled()) {
+        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        }else {
+        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        }
+        tessellator.setColorOpaque_F(brightness, brightness, brightness);
         double d = l.getIconUMin();
         double d1 = l.getIconUMax();
         double d2 = l.getIconVMin();
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelLantern.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelLantern.java
index 12909291f..e16c08709 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelLantern.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelLantern.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.util.helper.Side;
@@ -17,7 +18,13 @@ public class BlockModelLantern<T extends Block> extends BlockModelStandard<T> {
         boolean isHanging = (meta & 0b00000001) == 0;
         boolean isAngled = (meta & 0b00000010) != 0;
 
-        float brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        float brightness = 1.0f;
+        if(LightmapHelper.isLightmapEnabled()) {
+        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        }else {
+        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        }
+        tessellator.setColorOpaque_F(brightness, brightness, brightness);
 
         float yOffset = isHanging ? 0f : 0.375f;
 
@@ -124,8 +131,6 @@ public class BlockModelLantern<T extends Block> extends BlockModelStandard<T> {
         double hookMinV = texIndex.getSubIconV(onePix * 6);
         double hookMaxV = texIndex.getSubIconV(onePix * 10);
 
-        tessellator.setColorOpaque_F(brightness, brightness, brightness);
-
         // Render sides int
         tessellator.addVertexWithUV(intMaxX, intMinY, intMinZ, sideMinU, sideMaxV);
         tessellator.addVertexWithUV(intMinX, intMinY, intMinZ, sideMaxU, sideMaxV);
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java
index e7955c3ee..4d1034b65 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelLever.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.util.helper.Side;
@@ -54,12 +55,18 @@ public class BlockModelLever<T extends Block> extends BlockModelStandard<T>{
         {
             renderBlocks.overrideBlockTexture = null;
         }
-        float f3 = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
-        if(Block.lightEmission[block.id] > 0)
-        {
-            f3 = 1.0F;
+        float brightness = 1.0f;
+        if(LightmapHelper.isLightmapEnabled()) {
+        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        }else {
+			if(Block.lightEmission[block.id] > 0) {
+				brightness = 1.0f;
+			}else {
+				brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+			}
         }
-        tessellator.setColorOpaque_F(f3, f3, f3);
+        
+        tessellator.setColorOpaque_F(brightness, brightness, brightness);
         IconCoordinate texture = getBlockTextureFromSideAndMetadata(Side.BOTTOM, l);
         if(renderBlocks.overrideBlockTexture != null)
         {
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelPumpkinPie.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelPumpkinPie.java
new file mode 100644
index 000000000..ad91d66e4
--- /dev/null
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelPumpkinPie.java
@@ -0,0 +1,89 @@
+package net.minecraft.client.render.block.model;
+
+import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.stitcher.IconCoordinate;
+import net.minecraft.client.render.stitcher.TextureRegistry;
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.BlockCake;
+import net.minecraft.core.block.BlockEdible;
+import net.minecraft.core.util.helper.Side;
+
+public class BlockModelPumpkinPie<T extends Block> extends BlockModelStandard<T>{
+    protected IconCoordinate sideTexture = TextureRegistry.getTexture("minecraft:block/pumpkin_pie_side");
+    protected IconCoordinate insideTexture = TextureRegistry.getTexture("minecraft:block/pumpkin_pie_inside");
+    protected IconCoordinate topTexture = TextureRegistry.getTexture("minecraft:block/pumpkin_pie_top");
+
+    public BlockModelPumpkinPie(Block block) {
+        super(block);
+    }
+
+    public void renderSliceSide(Tessellator tessellator, Block block, int x, int y, int z, Side side, boolean overrideTex) {
+        if(overrideTex)
+            renderBlocks.overrideBlockTexture = insideTexture;
+        renderSide(tessellator, block, x, y, z, side, 0);
+        if(overrideTex)
+            renderBlocks.overrideBlockTexture = null;
+    }
+
+    private void renderSlice(Tessellator tessellator, Block block, int x, int y, int z, int sliceX, int sliceZ) {
+
+        double onePix = 0.0625;
+        double sliceWidth = onePix * 8;
+
+        double xMin = 0.0F + (sliceWidth * sliceX);
+        double xMax = xMin + sliceWidth;
+
+        double zMin =  0.0F + (sliceWidth * sliceZ);
+        double zMax = zMin + sliceWidth;
+        double offsetXMin = sliceX == 0 ? onePix : 0;
+        double offsetXMax = sliceX == 1 ? onePix : 0;
+        double offsetZMin = sliceZ == 0 ? onePix : 0;
+        double offsetZMax = sliceZ == 1 ? onePix : 0;
+
+        boolean insideSouth = sliceZ == 0;
+        boolean insideNorth = sliceZ == 1;
+        boolean insideEast = sliceX == 0 ;
+        boolean insideWest = sliceX == 1;
+
+        maxSlices = ((BlockEdible) block).maxBites;
+        block.setBlockBounds(xMin + offsetXMin, 0.0F, zMin + offsetZMin, xMax - offsetXMax, 0.375F, zMax - offsetZMax);
+        renderSide(tessellator, block, x, y, z, Side.TOP, 0);
+        renderSide(tessellator, block, x, y, z, Side.BOTTOM, 0);
+        renderSliceSide(tessellator, block, x, y, z, Side.SOUTH, insideSouth);
+        renderSliceSide(tessellator, block, x, y, z, Side.WEST, insideWest);
+        renderBlocks.flipTexture = true;
+        renderSliceSide(tessellator, block, x, y, z, Side.NORTH, insideNorth);
+        renderSliceSide(tessellator, block, x, y, z, Side.EAST, insideEast);
+        renderBlocks.flipTexture = false;
+    }
+
+    @Override
+    public boolean render(Tessellator tessellator, int x, int y, int z) {
+        block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
+
+        final int meta = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
+        renderBlocks.enableAO = true;
+        renderBlocks.cache.setupCache(block, renderBlocks.blockAccess, x, y, z);
+        int slices = 0;
+        for(int xSlice = 0; xSlice < 2; xSlice++){
+            for(int zSlice = 0; zSlice < 2; zSlice++) {
+                slices++;
+                if(meta >= slices)
+                    continue;
+                renderSlice(tessellator, block, x, y, z, xSlice, zSlice);
+            }
+        }
+
+        renderBlocks.enableAO = false;
+        return true;
+    }
+    @Override
+    public boolean shouldItemRender3d() {
+        return false;
+    }
+
+    public int maxSlices;
+
+
+
+}
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelRail.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelRail.java
index 7145f807d..5d5ff46ee 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelRail.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelRail.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.stitcher.IconCoordinate;
 import net.minecraft.client.render.stitcher.TextureRegistry;
 import net.minecraft.core.block.Block;
@@ -31,14 +32,26 @@ public class BlockModelRail<T extends BlockRail> extends BlockModelStandard<T> {
         {
             l &= 7;
         }
-        float f = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
-        if (renderBlocks.overbright)
-        {
-            i1 = getBlockOverbrightTexture(renderBlocks.blockAccess, x, y, z, 0);
-            if (i1 == null) return false;
-            f = 1.0f;
-        }
-        tessellator.setColorOpaque_F(f, f, f);
+		float brightness = 1.0f;
+		if(LightmapHelper.isLightmapEnabled()) {
+			if(renderBlocks.overbright) {
+				// TODO use correct skylight value, requires a getSavedLightValue method in WorldSource
+				tessellator.setLightmapCoord(LightmapHelper.getOverbrightLightmapCoord(0));
+			}else {
+				tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+			}
+		}else {
+			if(!renderBlocks.overbright) {
+				brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+			}
+		}
+		if(renderBlocks.overbright) {
+			i1 = getBlockOverbrightTexture(renderBlocks.blockAccess, x, y, z, 0);
+			if(i1 == null) {
+				return false;
+			}
+		}
+        tessellator.setColorOpaque_F(brightness, brightness, brightness);
         double d = i1.getIconUMin();
         double d1 = i1.getIconUMax();
         double d2 = i1.getIconVMin();
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java
index fe78ba935..b76f7f84f 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelRope.java
@@ -2,7 +2,10 @@ package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
 import net.minecraft.core.block.Block;
+import net.minecraft.core.block.BlockLanternFirefly;
 import net.minecraft.core.block.BlockRope;
+import net.minecraft.core.block.tag.BlockTags;
+import net.minecraft.core.util.helper.Side;
 import net.minecraft.core.world.WorldSource;
 
 public class BlockModelRope<T extends BlockRope>
@@ -14,13 +17,13 @@ extends BlockModelStandard<T> {
     @Override
     public boolean render(Tessellator tessellator, int x, int y, int z) {
         WorldSource world = renderBlocks.blockAccess;
-        boolean hasFloor = world.isBlockOpaqueCube(x, y - 1, z);
-        boolean hasBlockNegX = world.getBlockId(x - 1, y, z) == block.id;
-        boolean hasBlockPosX = world.getBlockId(x + 1, y, z) == block.id;
-        boolean hasBlockNegY = world.getBlockId(x, y - 1, z) == block.id || hasFloor;
-        boolean hasBlockPosY = world.getBlockId(x, y + 1, z) == block.id || world.isBlockOpaqueCube(x, y + 1, z);
-        boolean hasBlockNegZ = world.getBlockId(x, y, z - 1) == block.id;
-        boolean hasBlockPosZ = world.getBlockId(x, y, z + 1) == block.id;
+        boolean hasFloor = world.getBlock(x, y - 1, z) != null && world.getBlock(x, y - 1, z).canPlaceOnSurface();
+        boolean hasBlockNegX = canConnect(world, x, y, z, Side.WEST);
+        boolean hasBlockPosX = canConnect(world, x, y, z, Side.EAST);
+        boolean hasBlockNegY = canConnect(world, x, y, z, Side.BOTTOM) || hasFloor;
+        boolean hasBlockPosY = canConnect(world, x, y, z, Side.TOP);
+        boolean hasBlockNegZ = canConnect(world, x, y, z, Side.NORTH);
+        boolean hasBlockPosZ = canConnect(world, x, y, z, Side.SOUTH);
 
 
         boolean drawKnot =  !(hasBlockNegX && hasBlockPosX && !hasBlockNegY && !hasBlockPosY && !hasBlockNegZ && !hasBlockPosZ) &&
@@ -81,4 +84,19 @@ extends BlockModelStandard<T> {
 
         return true;
     }
+    private boolean canConnect(WorldSource worldSource, int x, int y, int z, Side side){
+        int blockX = x + side.getOffsetX();
+        int blockY = y + side.getOffsetY();
+        int blockZ = z + side.getOffsetZ();
+        Block _block = worldSource.getBlock(blockX, blockY, blockZ);
+        if (side == Side.BOTTOM){
+            if (_block instanceof BlockLanternFirefly && (worldSource.getBlockMetadata(blockX, blockY, blockZ) & 0b1) != 0){
+                return true;
+            }
+        } else if (side == Side.TOP) {
+            if (worldSource.isBlockOpaqueCube(blockX, blockY, blockZ) || BlockTags.CAN_HANG_OFF.appliesTo(_block)) return true;
+        }
+        if ((worldSource.getBlockMetadata(x, y, z) & 0b1000_0000) != 0 && worldSource.isBlockOpaqueCube(blockX, blockY, blockZ)) return true;
+        return _block == block;
+    }
 }
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java
index 3d2ae764f..2716a2b6c 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelSpikes.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockSpikes;
@@ -25,7 +26,12 @@ public class BlockModelSpikes<T extends Block> extends BlockModelStandard<T> {
         renderStandardBlock(tessellator, block, x, y, z);
 
         if(BlockSpikes.isSpikesUp(metaData)) {
-            float brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            float brightness = 1.0f;
+            if(LightmapHelper.isLightmapEnabled()) {
+            	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+            }else {
+            	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+            }
             tessellator.setColorOpaque_F(brightness, brightness, brightness);
             double uMin = texture.getIconUMin();
             double uMax = texture.getIconUMax();
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java
index 1d75ba6ac..c956b6df2 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelStandard.java
@@ -23,7 +23,7 @@ public class BlockModelStandard<T extends Block> extends BlockModel<T>{
     @Override
     public boolean render(Tessellator tessellator, int x, int y, int z) {
         block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
-        return renderStandardBlock(tessellator, block, x, y, z);
+        return renderStandardBlock(tessellator, block, x, y, z );
     }
 
     @Override
diff --git a/src/main/java/net/minecraft/client/render/block/model/BlockModelTorch.java b/src/main/java/net/minecraft/client/render/block/model/BlockModelTorch.java
index de235fe84..7d046bb50 100644
--- a/src/main/java/net/minecraft/client/render/block/model/BlockModelTorch.java
+++ b/src/main/java/net/minecraft/client/render/block/model/BlockModelTorch.java
@@ -1,6 +1,7 @@
 package net.minecraft.client.render.block.model;
 
 import net.minecraft.client.render.tessalator.Tessellator;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.stitcher.IconCoordinate;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.util.helper.Side;
@@ -14,12 +15,16 @@ public class BlockModelTorch<T extends Block> extends BlockModelStandard<T> {
     public boolean render(Tessellator tessellator, int x, int y, int z) {
         block.setBlockBoundsBasedOnState(renderBlocks.blockAccess, x, y, z);
         int l = renderBlocks.blockAccess.getBlockMetadata(x, y, z);
-        float f = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
-        if(Block.lightEmission[block.id] > 0)
-        {
-            f = 1.0F;
+        float brightness = 1.0f;
+        if(LightmapHelper.isLightmapEnabled()) {
+        	tessellator.setLightmapCoord(block.getLightmapCoord(renderBlocks.blockAccess, x, y, z));
+        }else {
+        	brightness = getBlockBrightness(renderBlocks.blockAccess, x, y, z);
+        	if(Block.lightEmission[block.id] > 0) {
+        		brightness = 1.0F;
+        	}
         }
-        tessellator.setColorOpaque_F(f, f, f);
+        tessellator.setColorOpaque_F(brightness, brightness, brightness);
         double d = 0.4;
         double d1 = 0.5D - d;
         double d2 = 0.2;
diff --git a/src/main/java/net/minecraft/client/render/entity/ArrowRenderer.java b/src/main/java/net/minecraft/client/render/entity/ArrowRenderer.java
index 60fa80cc9..6cf990707 100644
--- a/src/main/java/net/minecraft/client/render/entity/ArrowRenderer.java
+++ b/src/main/java/net/minecraft/client/render/entity/ArrowRenderer.java
@@ -12,11 +12,6 @@ public class ArrowRenderer extends EntityRenderer<EntityArrow>
     public void renderArrow(EntityArrow arrow, double x, double y, double z,
                             float yaw, float partialTick)
     {
-        if(arrow.yRotO == 0.0F && arrow.xRotO == 0.0F)
-        {
-            return;
-        }
-
         loadTexture("/item/arrows.png");
         GL11.glPushMatrix();
         GL11.glTranslatef((float)x, (float)y, (float)z);
diff --git a/src/main/java/net/minecraft/client/render/entity/PaintingRenderer.java b/src/main/java/net/minecraft/client/render/entity/PaintingRenderer.java
index 051eb176c..d5792995d 100644
--- a/src/main/java/net/minecraft/client/render/entity/PaintingRenderer.java
+++ b/src/main/java/net/minecraft/client/render/entity/PaintingRenderer.java
@@ -68,26 +68,34 @@ public class PaintingRenderer extends EntityRenderer<EntityPainting>
                 tessellator.addVertexWithUV(minX, maxY, maxZ, backMaxU, backMinV);
                 tessellator.addVertexWithUV(minX, minY, maxZ, backMaxU, backMaxV);
                 tessellator.addVertexWithUV(maxX, minY, maxZ, backMinU, backMaxV);
-                tessellator.setNormal(0.0F, 1.0F, 0.0F);
-                tessellator.addVertexWithUV(maxX, maxY, minZ, topBottomMinU, topBottomMinV);
-                tessellator.addVertexWithUV(minX, maxY, minZ, topBottomMaxU, topBottomMinV);
-                tessellator.addVertexWithUV(minX, maxY, maxZ, topBottomMaxU, topBottomMaxV);
-                tessellator.addVertexWithUV(maxX, maxY, maxZ, topBottomMinU, topBottomMaxV);
-                tessellator.setNormal(0.0F, -1F, 0.0F);
-                tessellator.addVertexWithUV(maxX, minY, maxZ, topBottomMinU, topBottomMinV);
-                tessellator.addVertexWithUV(minX, minY, maxZ, topBottomMaxU, topBottomMinV);
-                tessellator.addVertexWithUV(minX, minY, minZ, topBottomMaxU, topBottomMaxV);
-                tessellator.addVertexWithUV(maxX, minY, minZ, topBottomMinU, topBottomMaxV);
-                tessellator.setNormal(-1F, 0.0F, 0.0F);
-                tessellator.addVertexWithUV(maxX, maxY, maxZ, sidesMaxU, sidesMinV);
-                tessellator.addVertexWithUV(maxX, minY, maxZ, sidesMaxU, sidesMaxV);
-                tessellator.addVertexWithUV(maxX, minY, minZ, sidesMinU, sidesMaxV);
-                tessellator.addVertexWithUV(maxX, maxY, minZ, sidesMinU, sidesMinV);
-                tessellator.setNormal(1.0F, 0.0F, 0.0F);
-                tessellator.addVertexWithUV(minX, maxY, minZ, sidesMaxU, sidesMinV);
-                tessellator.addVertexWithUV(minX, minY, minZ, sidesMaxU, sidesMaxV);
-                tessellator.addVertexWithUV(minX, minY, maxZ, sidesMinU, sidesMaxV);
-                tessellator.addVertexWithUV(minX, maxY, maxZ, sidesMinU, sidesMinV);
+                if (y == tilesY - 1){
+                    tessellator.setNormal(0.0F, 1.0F, 0.0F);
+                    tessellator.addVertexWithUV(maxX, maxY, minZ, topBottomMinU, topBottomMinV);
+                    tessellator.addVertexWithUV(minX, maxY, minZ, topBottomMaxU, topBottomMinV);
+                    tessellator.addVertexWithUV(minX, maxY, maxZ, topBottomMaxU, topBottomMaxV);
+                    tessellator.addVertexWithUV(maxX, maxY, maxZ, topBottomMinU, topBottomMaxV);
+                }
+                if (y == 0){
+                    tessellator.setNormal(0.0F, -1F, 0.0F);
+                    tessellator.addVertexWithUV(maxX, minY, maxZ, topBottomMinU, topBottomMinV);
+                    tessellator.addVertexWithUV(minX, minY, maxZ, topBottomMaxU, topBottomMinV);
+                    tessellator.addVertexWithUV(minX, minY, minZ, topBottomMaxU, topBottomMaxV);
+                    tessellator.addVertexWithUV(maxX, minY, minZ, topBottomMinU, topBottomMaxV);
+                }
+                if (x == tilesX - 1){
+                    tessellator.setNormal(-1F, 0.0F, 0.0F);
+                    tessellator.addVertexWithUV(maxX, maxY, maxZ, sidesMaxU, sidesMinV);
+                    tessellator.addVertexWithUV(maxX, minY, maxZ, sidesMaxU, sidesMaxV);
+                    tessellator.addVertexWithUV(maxX, minY, minZ, sidesMinU, sidesMaxV);
+                    tessellator.addVertexWithUV(maxX, maxY, minZ, sidesMinU, sidesMinV);
+                }
+                if (x == 0){
+                    tessellator.setNormal(1.0F, 0.0F, 0.0F);
+                    tessellator.addVertexWithUV(minX, maxY, minZ, sidesMaxU, sidesMinV);
+                    tessellator.addVertexWithUV(minX, minY, minZ, sidesMaxU, sidesMaxV);
+                    tessellator.addVertexWithUV(minX, minY, maxZ, sidesMinU, sidesMaxV);
+                    tessellator.addVertexWithUV(minX, maxY, maxZ, sidesMinU, sidesMinV);
+                }
                 tessellator.draw();
             }
 
diff --git a/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java b/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
index 95f4761cb..bef9f0d97 100644
--- a/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
+++ b/src/main/java/net/minecraft/client/render/item/model/ItemModelDispatcher.java
@@ -144,6 +144,7 @@ public class ItemModelDispatcher extends Dispatcher<Item, ItemModel> {
         addDispatch(new ItemModelStandard(Item.bone, "minecraft").setFull3D());
         addDispatch(new ItemModelStandard(Item.dustSugar, "minecraft"));
         addDispatch(new ItemModelStandard(Item.foodCake, "minecraft"));
+        addDispatch(new ItemModelStandard(Item.foodPumpkinPie, "minecraft"));
         addDispatch(new ItemModelStandard(Item.bed, "minecraft"));
         addDispatch(new ItemModelStandard(Item.repeater, "minecraft"));
         addDispatch(new ItemModelStandard(Item.foodCookie, "minecraft"));
diff --git a/src/main/java/net/minecraft/client/render/shader/Shaders.java b/src/main/java/net/minecraft/client/render/shader/Shaders.java
index ee5041077..b30f7540f 100644
--- a/src/main/java/net/minecraft/client/render/shader/Shaders.java
+++ b/src/main/java/net/minecraft/client/render/shader/Shaders.java
@@ -103,10 +103,10 @@ public abstract class Shaders {
 			shader.uniformFloat("gMod", 1.0f);
 			shader.uniformFloat("bMod", 1.0f);
 		}
-		shader.uniformFloat("photoMode", minecraft.currentScreen != null && minecraft.currentScreen instanceof GuiPhotoMode);
+		shader.uniformFloat("photoMode", minecraft.currentScreen instanceof GuiPhotoMode);
 		shader.uniformFloat("guiOpened", minecraft.currentScreen != null);
 		
-		if(minecraft.currentScreen != null && minecraft.currentScreen instanceof GuiPhotoMode) {
+		if(minecraft.currentScreen instanceof GuiPhotoMode) {
 			GuiPhotoMode guiPhotoMode = (GuiPhotoMode) minecraft.currentScreen;
 			shader.uniformFloat("intensity", guiPhotoMode.intensityValue);
 		}else {
diff --git a/src/main/java/net/minecraft/client/render/shader/ShadersRenderer.java b/src/main/java/net/minecraft/client/render/shader/ShadersRenderer.java
index 5bd51824b..b5c93cd47 100644
--- a/src/main/java/net/minecraft/client/render/shader/ShadersRenderer.java
+++ b/src/main/java/net/minecraft/client/render/shader/ShadersRenderer.java
@@ -239,5 +239,7 @@ public class ShadersRenderer extends Renderer {
 			return internal;
 		}
 	}
-
+	public Texture getWorldFramebufferTex(){
+		return worldFramebufferTex;
+	}
 }
diff --git a/src/main/java/net/minecraft/client/render/tessalator/Tessellator.java b/src/main/java/net/minecraft/client/render/tessalator/Tessellator.java
index cef86fbf3..40c7a5fb8 100644
--- a/src/main/java/net/minecraft/client/render/tessalator/Tessellator.java
+++ b/src/main/java/net/minecraft/client/render/tessalator/Tessellator.java
@@ -5,6 +5,7 @@ public abstract class Tessellator {
     public abstract void startDrawingQuads();
     public abstract void startDrawing(int drawMode);
     public abstract void setTextureUV(double u, double v);
+    public abstract void setLightmapCoord(int lightmapCoord);
     public abstract void setColorOpaque_F(float r, float g, float b);
     public abstract void setColorRGBA_F(float r, float g, float b, float a);
     public abstract void setColorOpaque(int r, int g, int b);
diff --git a/src/main/java/net/minecraft/client/render/tessalator/TessellatorStandard.java b/src/main/java/net/minecraft/client/render/tessalator/TessellatorStandard.java
index 05a3eec62..da405a480 100644
--- a/src/main/java/net/minecraft/client/render/tessalator/TessellatorStandard.java
+++ b/src/main/java/net/minecraft/client/render/tessalator/TessellatorStandard.java
@@ -3,6 +3,7 @@ package net.minecraft.client.render.tessalator;
 import java.nio.*;
 
 import net.minecraft.client.Minecraft;
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.GLAllocation;
 import org.lwjgl.opengl.*;
 
@@ -13,8 +14,6 @@ import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
 
 public class TessellatorStandard extends Tessellator
 {
-    private boolean VBOsInitialized = false;
-
     TessellatorStandard(int bufferSize)
     {
         vertexCount = 0;
@@ -31,6 +30,7 @@ public class TessellatorStandard extends Tessellator
         byteBuffer = GLAllocation.createDirectByteBuffer(bufferSize * 4);
         intBuffer = byteBuffer.asIntBuffer();
         floatBuffer = byteBuffer.asFloatBuffer();
+        shortBuffer = byteBuffer.asShortBuffer();
         rawBuffer = new int[bufferSize];
         setUseVBO(Minecraft.getMinecraft(this).gameSettings.enableVbos.value);
     }
@@ -72,6 +72,20 @@ public class TessellatorStandard extends Tessellator
                 }
                 GL11.glEnableClientState(32888 /*GL_TEXTURE_COORD_ARRAY_EXT*/);
             }
+            if(hasLightmap)
+            {
+            	GL13.glClientActiveTexture(GL13.GL_TEXTURE1);
+            	
+            	if(useVBO) {
+            		GL11.glTexCoordPointer(2, GL11.GL_SHORT, 32, 28L);
+            	} else {
+            		shortBuffer.position(14);
+            		GL11.glTexCoordPointer(2, 32, shortBuffer);
+            	}
+            	
+            	GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+            	GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
+            }
             if(hasColor)
             {
                 if(useVBO)
@@ -117,6 +131,12 @@ public class TessellatorStandard extends Tessellator
             {
                 GL11.glDisableClientState(32888 /*GL_TEXTURE_COORD_ARRAY_EXT*/);
             }
+            if(hasLightmap)
+            {
+            	GL13.glClientActiveTexture(GL13.GL_TEXTURE1);
+            	GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
+            	GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
+            }
             if(hasColor)
             {
                 GL11.glDisableClientState(32886 /*GL_COLOR_ARRAY_EXT*/);
@@ -166,6 +186,18 @@ public class TessellatorStandard extends Tessellator
         textureU = u;
         textureV = v;
     }
+    
+    @Override
+    public void setLightmapCoord(int lightmapCoord) {
+    	if(!LightmapHelper.isLightmapEnabled()) {
+    		// Enabling the texture coordinates while the lightmap is disabled shouldn't cause any issues,
+    		// but it might be a little bit slower, so we make sure that never happens!
+    		
+    		throw new IllegalStateException("Lightmap is disabled!");
+    	}
+    	hasLightmap = true;
+    	this.lightmapCoord = lightmapCoord;
+    }
 
     public void setColorOpaque_F(float r, float g, float b)
     {
@@ -249,6 +281,10 @@ public class TessellatorStandard extends Tessellator
                     rawBuffer[rawBufferIndex + 3] = rawBuffer[(rawBufferIndex - j) + 3];
                     rawBuffer[rawBufferIndex + 4] = rawBuffer[(rawBufferIndex - j) + 4];
                 }
+                if(hasLightmap)
+                {
+                	rawBuffer[rawBufferIndex + 7] = rawBuffer[(rawBufferIndex - j) + 7];
+                }
                 if(hasColor)
                 {
                     rawBuffer[rawBufferIndex + 5] = rawBuffer[(rawBufferIndex - j) + 5];
@@ -266,6 +302,9 @@ public class TessellatorStandard extends Tessellator
             rawBuffer[rawBufferIndex + 3] = Float.floatToRawIntBits((float)textureU);
             rawBuffer[rawBufferIndex + 4] = Float.floatToRawIntBits((float)textureV);
         }
+        if(hasLightmap) {
+        	rawBuffer[rawBufferIndex + 7] = lightmapCoord;
+        }
         if(hasColor)
         {
             rawBuffer[rawBufferIndex + 5] = color;
@@ -364,14 +403,17 @@ public class TessellatorStandard extends Tessellator
     private ByteBuffer byteBuffer;
     private IntBuffer intBuffer;
     private FloatBuffer floatBuffer;
+    private ShortBuffer shortBuffer;
     private int rawBuffer[];
     private int vertexCount;
     private double textureU;
     private double textureV;
+    private int lightmapCoord;
     private int color;
     private boolean hasColor;
     private boolean hasTexture;
     private boolean hasNormals;
+    private boolean hasLightmap;
     private int rawBufferIndex;
     private int addedVertices;
     private boolean isColorDisabled;
diff --git a/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlag.java b/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlag.java
index 69f42776a..958efc0d4 100644
--- a/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlag.java
+++ b/src/main/java/net/minecraft/client/render/tileentity/TileEntityRendererFlag.java
@@ -16,6 +16,7 @@ public class TileEntityRendererFlag extends TileEntityRenderer<TileEntityFlag>
 
     private final ModelFlag flagModel;
     private FlagRenderer flagRenderer = null;
+    private long lastTick = 0;
     
     public TileEntityRendererFlag() 
     {
@@ -43,7 +44,11 @@ public class TileEntityRendererFlag extends TileEntityRenderer<TileEntityFlag>
         }
         flagRenderer.updateTexture(tileEntity);
 
-        float sway = (float) (((Minecraft.getMinecraft(this).theWorld.getWorldTime() + (double)partialTick) / 1.5D) % (2 * Math.PI));
+        long currentTick = Minecraft.getMinecraft(this).theWorld.getWorldTime();
+
+        float sway = (float) (((lastTick + (currentTick - lastTick) * (double)partialTick) / 1.5D) % (2 * Math.PI));
+
+        lastTick = currentTick;
 
         GL11.glPushMatrix();
         final float scale = 1F;
diff --git a/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderViewer.java b/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderViewer.java
new file mode 100644
index 000000000..1819a8502
--- /dev/null
+++ b/src/main/java/net/minecraft/client/world/chunk/provider/ChunkProviderViewer.java
@@ -0,0 +1,77 @@
+package net.minecraft.client.world.chunk.provider;
+
+import net.minecraft.core.world.ProgressListener;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.chunk.Chunk;
+import net.minecraft.core.world.chunk.DisplayChunk;
+import net.minecraft.core.world.chunk.EmptyChunk;
+import net.minecraft.core.world.chunk.provider.IChunkProvider;
+
+public class ChunkProviderViewer implements IChunkProvider {
+    public final Chunk blankChunk;
+    public final Chunk displayChunk;
+    public ChunkProviderViewer(World world){
+        blankChunk = new EmptyChunk(world, 0, 0);
+        displayChunk = new DisplayChunk(world, 0, 0);
+    }
+    @Override
+    public boolean isChunkLoaded(int chunkX, int chunkZ) {
+        return true;
+    }
+
+    @Override
+    public Chunk provideChunk(int chunkX, int chunkZ) {
+        if (chunkX == 0 && chunkZ == 0){
+            return displayChunk;
+        }
+        return blankChunk;
+    }
+
+    @Override
+    public Chunk prepareChunk(int chunkX, int chunkZ) {
+        if (chunkX == 0 && chunkZ == 0){
+            return displayChunk;
+        }
+        return blankChunk;
+    }
+
+    @Override
+    public void regenerateChunk(int chunkX, int chunkZ) {
+
+    }
+
+    @Override
+    public void populate(IChunkProvider chunkProvider, int chunkX, int chunkZ) {
+
+    }
+
+    @Override
+    public boolean saveChunks(boolean saveImmediately, ProgressListener progressUpdate) {
+        return false;
+    }
+
+    @Override
+    public boolean tick() {
+        return false;
+    }
+
+    @Override
+    public boolean canSave() {
+        return false;
+    }
+
+    @Override
+    public String getInfoString() {
+        return null;
+    }
+
+    @Override
+    public void unloadAllChunks() {
+
+    }
+
+    @Override
+    public void setCurrentChunkOver(int chunkX, int chunkZ) {
+
+    }
+}
diff --git a/src/main/java/net/minecraft/core/block/Block.java b/src/main/java/net/minecraft/core/block/Block.java
index 094edce19..c2bbff2fe 100644
--- a/src/main/java/net/minecraft/core/block/Block.java
+++ b/src/main/java/net/minecraft/core/block/Block.java
@@ -199,10 +199,20 @@ public class Block
         this.maxZ = maxZ;
     }
 
-    public float getBlockBrightness(WorldSource blockAccess, int x, int y, int z)
-    {
-        return blockAccess.getBrightness(x, y, z, lightEmission[id]);
-    }
+	public float getBlockBrightness(WorldSource blockAccess, int x, int y, int z) {
+		return blockAccess.getBrightness(x, y, z, lightEmission[id]);
+	}
+
+	public int getLightmapCoord(WorldSource blockAccess, int x, int y, int z) {
+		return blockAccess.getLightmapCoord(x, y, z, lightEmission[id]);
+	}
+	
+	/**
+	 * Used when fullbright or lightmap is active 
+	 */
+	public float getAmbientOcclusionStrength(WorldSource blockAccess, int x, int y, int z) {
+		return isSolidRender() ? 1.0f : 0.0f;
+	}
 
     public boolean shouldSideBeRendered(WorldSource blockAccess, int x, int y, int z, int side)
     {
@@ -818,7 +828,7 @@ public class Block
     public static final Block wool = new BlockWool("wool", 110).withHardness(0.8F).withDisabledNeighborNotifyOnMetadataChange()
             .withTags(BlockTags.MINEABLE_BY_SHEARS);
     public static final Block rope = new BlockRope("rope", 111).withHardness(0.0F).withDisabledStats().withDisabledNeighborNotifyOnMetadataChange()
-            .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.PREVENT_MOB_SPAWNS);
+            .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.PREVENT_MOB_SPAWNS, BlockTags.CAN_HANG_OFF);
 
     public static final Block brickClay = new Block("brick.clay", 120, Material.stone).withHardness(3.0F).withBlastResistance(10F)
             .withTags(BlockTags.MINEABLE_BY_PICKAXE);
@@ -1230,9 +1240,9 @@ public class Block
             .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_PICKAXE);
 
     public static final Block mesh = new BlockMesh("mesh", 600).withHardness(1.5F)
-            .withTags(BlockTags.MINEABLE_BY_PICKAXE);
+            .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CAN_HANG_OFF);
     public static final Block meshGold = new BlockMeshGold("mesh.gold", 601).withHardness(1F)
-            .withTags(BlockTags.MINEABLE_BY_PICKAXE);
+            .withTags(BlockTags.MINEABLE_BY_PICKAXE, BlockTags.CAN_HANG_OFF);
     
     public static final Block bed = new BlockBed("bed", 610).withHardness(0.2F).withDisabledStats().withDisabledNeighborNotifyOnMetadataChange().withLitInteriorSurface(true)
             .withTags(BlockTags.NOT_IN_CREATIVE_MENU, BlockTags.MINEABLE_BY_AXE);
@@ -1350,6 +1360,8 @@ public class Block
 
     public static final Block cake = new BlockCake("cake", 840).withHardness(0.5F).withDisabledStats().withDisabledNeighborNotifyOnMetadataChange()
             .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU);
+    public static final Block pumpkinPie = new BlockPumpkinPie("pumpkin_pie", 841).withHardness(0.5F).withDisabledStats().withDisabledNeighborNotifyOnMetadataChange()
+            .withTags(BlockTags.BROKEN_BY_FLUIDS, BlockTags.NOT_IN_CREATIVE_MENU);
 
     public static final Block lampIdle = new BlockLamp("lamp.idle", 850, false).withHardness(0.5F).withDisabledStats().withDisabledNeighborNotifyOnMetadataChange()
             .withTags(BlockTags.MINEABLE_BY_PICKAXE);
@@ -1416,7 +1428,10 @@ public class Block
     	((BlockLanternFirefly)lanternFireflyBlue).setItem(Item.lanternFireflyBlue);
         ((BlockLanternFirefly)lanternFireflyRed).setItem(Item.lanternFireflyRed);
         ((BlockJar)jarGlass).setItem(Item.jar);
-    	
+
+        ((BlockEdible)cake).setItem(Item.foodCake);
+        ((BlockEdible)pumpkinPie).setItem(Item.foodPumpkinPie);
+
         BlockMoss.initMossMap();
 
         ((BlockLayerBase)layerSnow).setFullBlockID(Block.blockSnow.id);
diff --git a/src/main/java/net/minecraft/core/block/BlockCake.java b/src/main/java/net/minecraft/core/block/BlockCake.java
index 70938f019..672778d78 100644
--- a/src/main/java/net/minecraft/core/block/BlockCake.java
+++ b/src/main/java/net/minecraft/core/block/BlockCake.java
@@ -1,37 +1,14 @@
 package net.minecraft.core.block;
 
-import net.minecraft.core.block.entity.TileEntity;
-import net.minecraft.core.block.material.Material;
-import net.minecraft.core.entity.player.EntityPlayer;
-import net.minecraft.core.enums.EnumDropCause;
-import net.minecraft.core.item.Item;
-import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.phys.AABB;
-import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
 
-// Referenced classes of package net.minecraft.src:
-//            Block, Material, IBlockAccess, World, 
-//            AxisAlignedBB, EntityPlayer
-
-public class BlockCake extends Block
+public class BlockCake extends BlockEdible
 {
 
 	public BlockCake(String key, int id)
     {
-        super(key, id, Material.cake);
-        setTicking(true);
-    }
-
-    @Override
-    public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int x, int y, int z, int meta, TileEntity tileEntity)
-    {
-        if (dropCause == EnumDropCause.PICK_BLOCK || meta == 0)
-        {
-            return new ItemStack[]{new ItemStack(Item.foodCake)};
-        }
-
-        return null;
+        super(key, id, 6, 3);
     }
 
     @Override
@@ -64,72 +41,4 @@ public class BlockCake extends Block
         return AABB.getBoundingBoxFromPool((float) x + f1, y, (float) z + f, (float)(x + 1) - f, (float) y + f2, (float)(z + 1) - f);
     }
 
-    @Override
-	public boolean renderAsNormalBlock()
-    {
-        return false;
-    }
-
-    @Override
-	public boolean isSolidRender()
-    {
-        return false;
-    }
-
-    @Override
-    public boolean blockActivated(World world, int x, int y, int z, EntityPlayer player)
-    {
-        eatCakeSlice(world, x, y, z, player);
-        return true;
-    }
-
-    @Override
-    public void onBlockClicked(World world, int x, int y, int z, EntityPlayer player)
-    {
-        eatCakeSlice(world, x, y, z, player);
-    }
-
-    private void eatCakeSlice(World world, int i, int j, int k, EntityPlayer entityplayer)
-    {
-        if(entityplayer.getHealth() < entityplayer.getMaxHealth())
-        {
-            entityplayer.heal(3);
-            int l = world.getBlockMetadata(i, j, k) + 1;
-            if(l >= 6)
-            {
-                world.setBlockWithNotify(i, j, k, 0);
-            } else
-            {
-                world.setBlockMetadataWithNotify(i, j, k, l);
-                world.markBlockDirty(i, j, k);
-            }
-        }
-    }
-
-    @Override
-	public boolean canPlaceBlockAt(World world, int x, int y, int z)
-    {
-        if(!super.canPlaceBlockAt(world, x, y, z))
-        {
-            return false;
-        } else
-        {
-            return canBlockStay(world, x, y, z);
-        }
-    }
-
-    @Override
-	public void onNeighborBlockChange(World world, int x, int y, int z, int blockId)
-    {
-        if(!canBlockStay(world, x, y, z))
-        {
-            world.setBlockWithNotify(x, y, z, 0);
-        }
-    }
-
-    @Override
-    public boolean canBlockStay(World world, int x, int y, int z)
-    {
-        return world.getBlockMaterial(x, y - 1, z).isSolid();
-    }
 }
diff --git a/src/main/java/net/minecraft/core/block/BlockChestLegacy.java b/src/main/java/net/minecraft/core/block/BlockChestLegacy.java
index 7a2c8e86f..f647566d7 100644
--- a/src/main/java/net/minecraft/core/block/BlockChestLegacy.java
+++ b/src/main/java/net/minecraft/core/block/BlockChestLegacy.java
@@ -25,7 +25,7 @@ public class BlockChestLegacy extends BlockTileEntity {
 		}
 		Block block = world.getBlock(x, y, z);
 		if(block != null) {
-			return block.getBreakResult(world, dropCause, x, y, z, meta, tileEntity);
+			return super.getBreakResult(world, dropCause, x, y, z, meta, tileEntity);
 		}
 		return null;
 	}
diff --git a/src/main/java/net/minecraft/core/block/BlockEdible.java b/src/main/java/net/minecraft/core/block/BlockEdible.java
new file mode 100644
index 000000000..fde544c91
--- /dev/null
+++ b/src/main/java/net/minecraft/core/block/BlockEdible.java
@@ -0,0 +1,109 @@
+package net.minecraft.core.block;
+
+import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.player.EntityPlayer;
+import net.minecraft.core.enums.EnumDropCause;
+import net.minecraft.core.item.Item;
+import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.world.World;
+
+public abstract class BlockEdible extends Block {
+
+    public BlockEdible(String key, int id, int maxBites, int healAmount)
+    {
+        super(key, id, Material.cake);
+        this.maxBites = maxBites;
+        this.healAmount = healAmount;
+        setTicking(true);
+    }
+
+    @Override
+    public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int x, int y, int z, int meta, TileEntity tileEntity)
+    {
+        if (dropCause == EnumDropCause.PICK_BLOCK || meta == 0)
+        {
+            return new ItemStack[]{new ItemStack(item)};
+        }
+
+        return null;
+    }
+
+    @Override
+    public boolean renderAsNormalBlock()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isSolidRender()
+    {
+        return false;
+    }
+
+    private void eatSlice(World world, int x, int y, int z, EntityPlayer entityplayer)
+    {
+        if(entityplayer.getHealth() < entityplayer.getMaxHealth())
+        {
+            entityplayer.heal(healAmount);
+            int data = world.getBlockMetadata(x, y, z) + 1;
+            if(data >= maxBites)
+            {
+                world.setBlockWithNotify(x, y, z, 0);
+            } else
+            {
+                world.setBlockMetadataWithNotify(x, y, z, data);
+                world.markBlockDirty(x, y, z);
+            }
+        }
+    }
+
+    @Override
+    public boolean blockActivated(World world, int x, int y, int z, EntityPlayer player)
+    {
+        eatSlice(world, x, y, z, player);
+        return true;
+    }
+
+    @Override
+    public void onBlockClicked(World world, int x, int y, int z, EntityPlayer player)
+    {
+        eatSlice(world, x, y, z, player);
+    }
+
+    @Override
+    public boolean canPlaceBlockAt(World world, int x, int y, int z)
+    {
+        if(!super.canPlaceBlockAt(world, x, y, z))
+        {
+            return false;
+        } else
+        {
+            return canBlockStay(world, x, y, z);
+        }
+    }
+
+    @Override
+    public void onNeighborBlockChange(World world, int x, int y, int z, int blockId)
+    {
+        if(!canBlockStay(world, x, y, z))
+        {
+            world.setBlockWithNotify(x, y, z, 0);
+        }
+    }
+
+    @Override
+    public boolean canBlockStay(World world, int x, int y, int z)
+    {
+        return world.getBlockMaterial(x, y - 1, z).isSolid();
+    }
+
+    public void setItem(Item item) {
+        this.item = item;
+    }
+
+    public Item item;
+    public int maxBites;
+    public int healAmount;
+
+}
diff --git a/src/main/java/net/minecraft/core/block/BlockLeavesBase.java b/src/main/java/net/minecraft/core/block/BlockLeavesBase.java
index ab68601f5..dc177788e 100644
--- a/src/main/java/net/minecraft/core/block/BlockLeavesBase.java
+++ b/src/main/java/net/minecraft/core/block/BlockLeavesBase.java
@@ -1,17 +1,16 @@
 package net.minecraft.core.block;
 
-import net.minecraft.client.entity.fx.EntityLeafFX;
+import java.util.Random;
+
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
-import net.minecraft.core.entity.Entity;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.ItemStack;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.world.World;
+import net.minecraft.core.world.WorldSource;
 import net.minecraft.core.world.season.Season;
 
-import java.util.Random;
-
 // Referenced classes of package net.minecraft.src:
 //            Block, IBlockAccess, Material
 
@@ -186,6 +185,11 @@ public abstract class BlockLeavesBase extends Block
     public static boolean isPermanent(int meta) {
     	return (meta & 0b1) > 0;
     }
+    
+    @Override
+    public float getAmbientOcclusionStrength(WorldSource blockAccess, int x, int y, int z) {
+    	return 1.0f;
+    }
 
     int[] adjacentTreeBlocks;
 }
diff --git a/src/main/java/net/minecraft/core/block/BlockPumpkinPie.java b/src/main/java/net/minecraft/core/block/BlockPumpkinPie.java
new file mode 100644
index 000000000..61813f766
--- /dev/null
+++ b/src/main/java/net/minecraft/core/block/BlockPumpkinPie.java
@@ -0,0 +1,51 @@
+package net.minecraft.core.block;
+
+import net.minecraft.core.sound.SoundCategory;
+import net.minecraft.core.util.phys.AABB;
+import net.minecraft.core.world.World;
+import net.minecraft.core.world.WorldSource;
+
+import java.util.Random;
+
+public class BlockPumpkinPie extends BlockEdible
+{
+
+    public BlockPumpkinPie(String key, int id)
+    {
+        super(key, id, 4, 5);
+    }
+
+    @Override
+    public void setBlockBoundsBasedOnState(WorldSource world, int x, int y, int z)
+    {
+        int l = world.getBlockMetadata(x, y, z);
+        float f = 0.0625F;
+        float xMin = l >= 2 ? 0.5f : f;
+        float zMin = l >= 3 ? 0.5f : f;
+        float f2 = 0.4375F;
+        setBlockBounds(xMin, 0.0F, zMin, 1.0F - f, f2, 1.0F - f);
+    }
+
+    @Override
+    public AABB getCollisionBoundingBoxFromPool(WorldSource world, int x, int y, int z)
+    {
+        int l = world.getBlockMetadata(x, y, z);
+        float f = 0.0625F;
+        float xMin = l >= 2 ? 0.5f : f;
+        float zMin = l >= 3 ? 0.5f : f;
+        float f2 = 0.4375F;
+        return AABB.getBoundingBoxFromPool((float) x + xMin, y, (float) z + zMin, (float)(x + 1) - f, ((float) y + f2) - f, (float)(z + 1) - f);
+    }
+
+    @Override
+    public AABB getSelectedBoundingBoxFromPool(WorldSource world, int x, int y, int z)
+    {
+        int l = world.getBlockMetadata(x, y, z);
+        float f = 0.0625F;
+        float xMin = l >= 2 ? 0.5f : f;
+        float zMin = l >= 3 ? 0.5f : f;
+        float f2 = 0.4375F;
+        return AABB.getBoundingBoxFromPool((float) x + xMin, y, (float) z + zMin, (float)(x + 1) - f, ((float) y + f2) - f, (float)(z + 1) - f);
+    }
+
+}
diff --git a/src/main/java/net/minecraft/core/block/BlockRope.java b/src/main/java/net/minecraft/core/block/BlockRope.java
index 4867ec371..e55537a66 100644
--- a/src/main/java/net/minecraft/core/block/BlockRope.java
+++ b/src/main/java/net/minecraft/core/block/BlockRope.java
@@ -1,10 +1,13 @@
 package net.minecraft.core.block;
 
 import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.entity.TileEntityNote;
 import net.minecraft.core.block.material.Material;
+import net.minecraft.core.entity.player.EntityPlayer;
 import net.minecraft.core.enums.EnumDropCause;
 import net.minecraft.core.item.Item;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.item.ItemToolShears;
 import net.minecraft.core.util.phys.AABB;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.WorldSource;
@@ -61,6 +64,22 @@ public class BlockRope
 
         setBlockBounds(minX, minY, minZ, maxX, maxY, maxZ);
     }
+    @Override
+    public boolean blockActivated(World world, int x, int y, int z, EntityPlayer player)
+    {
+        ItemStack heldItem = player.getHeldItem();
+        if (heldItem != null && heldItem.getItem() instanceof ItemToolShears){
+            int meta = world.getBlockMetadata(x, y, z);
+            int forceRope = (~meta) & 0b1000_0000;
+            world.setBlockMetadataWithNotify(x, y, z, forceRope | (meta & 0b0111_1111));
+            heldItem.damageItem(1, player);
+            if (heldItem.stackSize <= 0){
+                player.destroyCurrentEquippedItem();
+            }
+            return true;
+        }
+        return false;
+    }
 
     @Override
     public ItemStack[] getBreakResult(World world, EnumDropCause dropCause, int x, int y, int z, int meta, TileEntity tileEntity) {
diff --git a/src/main/java/net/minecraft/core/block/BlockTorch.java b/src/main/java/net/minecraft/core/block/BlockTorch.java
index 089334c83..00b469fb5 100644
--- a/src/main/java/net/minecraft/core/block/BlockTorch.java
+++ b/src/main/java/net/minecraft/core/block/BlockTorch.java
@@ -244,4 +244,9 @@ public class BlockTorch extends Block
             world.spawnParticle("flame", xPos, yPos, zPos, 0.0D, 0.0D, 0.0D);
         }
     }
+    
+    @Override
+    public int getLightmapCoord(WorldSource blockAccess, int x, int y, int z) {
+		return blockAccess.getLightmapCoord(x, y, z, lightEmission[id] > 0 ? 15 : 0);
+    }
 }
diff --git a/src/main/java/net/minecraft/core/entity/ConsumedFood.java b/src/main/java/net/minecraft/core/entity/ConsumedFood.java
index 920164a73..b3777b165 100644
--- a/src/main/java/net/minecraft/core/entity/ConsumedFood.java
+++ b/src/main/java/net/minecraft/core/entity/ConsumedFood.java
@@ -19,6 +19,10 @@ public class ConsumedFood {
         healRemaining += food.getHealAmount();
     }
 
+    public int getHealRemaining(){
+        return this.healRemaining;
+    }
+
     public boolean isFinished() {
         return healRemaining <= 0;
     }
diff --git a/src/main/java/net/minecraft/core/entity/Entity.java b/src/main/java/net/minecraft/core/entity/Entity.java
index ed5ff671b..3e6853b5e 100644
--- a/src/main/java/net/minecraft/core/entity/Entity.java
+++ b/src/main/java/net/minecraft/core/entity/Entity.java
@@ -8,6 +8,7 @@ import com.mojang.nbt.DoubleTag;
 import com.mojang.nbt.FloatTag;
 import com.mojang.nbt.ListTag;
 
+import net.minecraft.client.gui.guidebook.mobs.MobInfoRegistry;
 import net.minecraft.core.Global;
 import net.minecraft.core.block.Block;
 import net.minecraft.core.block.BlockFluid;
@@ -16,6 +17,7 @@ import net.minecraft.core.block.tag.BlockTags;
 import net.minecraft.core.entity.player.EntityPlayer;
 import net.minecraft.core.enums.EnumBlockSoundEffectType;
 import net.minecraft.core.item.ItemStack;
+import net.minecraft.core.lang.I18n;
 import net.minecraft.core.util.helper.DamageType;
 import net.minecraft.core.util.helper.MathHelper;
 import net.minecraft.core.util.phys.AABB;
@@ -1453,4 +1455,19 @@ public abstract class Entity
     public float getXRotDelta() {
         return xRot - xRotO;
     }
+
+    public static String getNameFromEntity(Entity entity, boolean useNickname){
+        I18n translator = I18n.getInstance();
+        if (entity instanceof EntityLiving && useNickname){
+            if (!((EntityLiving) entity).nickname.isEmpty()){
+                return ((EntityLiving) entity).nickname;
+            }
+        }
+        if (MobInfoRegistry.getMobInfo(entity.getClass()) != null){
+            return translator.translateKey(MobInfoRegistry.getMobInfo(entity.getClass()).getNameTranslationKey());
+        }
+        String dispatcherName = EntityDispatcher.getEntityString(entity);
+        if (dispatcherName != null) return dispatcherName;
+        return entity.getClass().getSimpleName();
+    }
 }
diff --git a/src/main/java/net/minecraft/core/entity/EntityDispatcher.java b/src/main/java/net/minecraft/core/entity/EntityDispatcher.java
index a430c79f1..a8044bf50 100644
--- a/src/main/java/net/minecraft/core/entity/EntityDispatcher.java
+++ b/src/main/java/net/minecraft/core/entity/EntityDispatcher.java
@@ -49,6 +49,7 @@ public class EntityDispatcher
         catch(Exception exception)
         {
             exception.printStackTrace();
+            System.out.println("Error with id '" + s + "'");
         }
         return entity;
     }
diff --git a/src/main/java/net/minecraft/core/entity/EntityLiving.java b/src/main/java/net/minecraft/core/entity/EntityLiving.java
index b15c41f72..65ab75554 100644
--- a/src/main/java/net/minecraft/core/entity/EntityLiving.java
+++ b/src/main/java/net/minecraft/core/entity/EntityLiving.java
@@ -148,12 +148,10 @@ public abstract class EntityLiving extends Entity
         ItemStack item = entityplayer.inventory.getCurrentItem();
         if (item != null && item.itemID == Item.label.id && item.hasCustomName())
         {
-            nickname = StringUtils.substring(item.getCustomName(), 0, 32);
             if(item.hasCustomColor()) {
             	this.chatColor = item.getCustomColor();
             }
-            hadNicknameSet = true;
-            onLabelled();
+            setNickname(StringUtils.substring(item.getCustomName(), 0, 32));
             return false;
         }
 
@@ -163,6 +161,11 @@ public abstract class EntityLiving extends Entity
     protected void onLabelled()
     {
     }
+    public void setNickname(String nickname){
+        this.nickname = nickname;
+        hadNicknameSet = true;
+        onLabelled();
+    }
 
     public void playLivingSound()
     {
@@ -232,12 +235,16 @@ public abstract class EntityLiving extends Entity
 
             }
         }
+        List<ItemFood> finishedFood = new ArrayList<>();
         for (Map.Entry<ItemFood, ConsumedFood> entry : consumedFood.entrySet()) {
             entry.getValue().tick();
             if (entry.getValue().isFinished()) {
-                consumedFood.remove(entry.getKey());
+                finishedFood.add(entry.getKey());
             }
         }
+        for (ItemFood food : finishedFood) {
+            consumedFood.remove(food);
+        }
         prevRotationUnused = unusedRotation1;
         prevRenderYawOffset = renderYawOffset;
         yRotO = yRot;
@@ -391,6 +398,15 @@ public abstract class EntityLiving extends Entity
         return 10;
     }
 
+    public int getTotalHealingRemaining(){
+        int totalHealingRemaining = 0;
+        for (ConsumedFood value :
+             consumedFood.values()) {
+            totalHealingRemaining += value.getHealRemaining();
+        }
+        return totalHealingRemaining;
+    }
+
     public void eatFood(ItemFood food) {
         if (food == null) return;
         if (food.getTicksPerHeal() == 0) {
diff --git a/src/main/java/net/minecraft/core/entity/animal/EntityWolf.java b/src/main/java/net/minecraft/core/entity/animal/EntityWolf.java
index e8b1e4ea4..662a5ad6a 100644
--- a/src/main/java/net/minecraft/core/entity/animal/EntityWolf.java
+++ b/src/main/java/net/minecraft/core/entity/animal/EntityWolf.java
@@ -882,7 +882,7 @@ public class EntityWolf extends EntityAnimal
     private float timeWolfIsShaking;
     private float prevTimeWolfIsShaking;
     private ItemStack armor = null;
-    private static final Map<ArmorMaterial, ItemArmor> ARMOR_MATERIALS = new HashMap<>();
+    public static final Map<ArmorMaterial, ItemArmor> ARMOR_MATERIALS = new HashMap<>();
     static {
         ARMOR_MATERIALS.put(ArmorMaterial.LEATHER, (ItemArmor) Item.armorChestplateLeather);
         ARMOR_MATERIALS.put(ArmorMaterial.CHAINMAIL, (ItemArmor) Item.armorChestplateChainmail);
diff --git a/src/main/java/net/minecraft/core/entity/monster/EntityArmoredZombie.java b/src/main/java/net/minecraft/core/entity/monster/EntityArmoredZombie.java
index dba29fc38..dbc518430 100644
--- a/src/main/java/net/minecraft/core/entity/monster/EntityArmoredZombie.java
+++ b/src/main/java/net/minecraft/core/entity/monster/EntityArmoredZombie.java
@@ -19,14 +19,13 @@ import java.util.Random;
 
 public class EntityArmoredZombie extends EntityZombie
 {
-    private final boolean isHoldingSword;
+    private boolean isHoldingSword;
     public EntityArmoredZombie(World world)
     {
         super(world);
         skinName = "zombie_armored";
         Random rand = new Random();
-        isHoldingSword = rand.nextInt(5)==0;
-        attackStrength += isHoldingSword ? 2:0;
+        setHoldingSword(rand.nextInt(5)==0);
         List<Integer> armorItems = new ArrayList<>();
         armorItems.add(0);
         armorItems.add(1);
@@ -109,6 +108,10 @@ public class EntityArmoredZombie extends EntityZombie
         short value = entityData.getShort(7);
         return new int[]{value & 0x3, (value & 0xC) >> 2, (value & 0x30) >> 4, (value & 0xC0) >> 6};
     }
+    public void setHoldingSword(boolean flag){
+        isHoldingSword = flag;
+        attackStrength = isHoldingSword? 7:5;
+    }
 
     @Override
 	public ItemStack getHeldItem()
diff --git a/src/main/java/net/minecraft/core/entity/monster/EntitySnowman.java b/src/main/java/net/minecraft/core/entity/monster/EntitySnowman.java
index 5d7bbb07c..ec36a28fc 100644
--- a/src/main/java/net/minecraft/core/entity/monster/EntitySnowman.java
+++ b/src/main/java/net/minecraft/core/entity/monster/EntitySnowman.java
@@ -108,18 +108,9 @@ public class EntitySnowman extends EntityMonster
     @Override
     protected void dropFewItems()
     {
-        int i = Item.ammoSnowball.id;
-        if(i > 0)
-        {
-            int j = random.nextInt(3);
-            if (random.nextInt(1000) == 0) {
-                id = Item.bucketIcecream.id;
-                j = 1;
-            }
-            for(int k = 0; k < j; k++)
-            {
-                spawnAtLocation(i, 1);
-            }
+        if (random.nextInt(1000) == 0){
+            spawnAtLocation(Item.bucketIcecream.id, 1);
         }
+        super.dropFewItems();
     }
 }
diff --git a/src/main/java/net/minecraft/core/item/Item.java b/src/main/java/net/minecraft/core/item/Item.java
index f26d8c7d1..1e9991be0 100644
--- a/src/main/java/net/minecraft/core/item/Item.java
+++ b/src/main/java/net/minecraft/core/item/Item.java
@@ -425,7 +425,8 @@ public class Item
     public static Item seat = new ItemPlaceable("seat", 16531, Block.seat).setMaxStackSize(64);
     public static Item doorOakPainted = (new ItemDoorPainted("door.oak.painted", 16532, Block.doorPlanksOakPaintedBottom, Block.doorPlanksOakPaintedTop));
     public static Item doorGlass = (new ItemDoor("door.glass", 16533, Block.doorGlassBottom, Block.doorGlassTop));
-    public static Item rope = new ItemPlaceable("rope", 16534, Block.rope);
+    public static Item rope = new ItemRope("rope", 16534, Block.rope);
+    public static Item foodPumpkinPie = (new ItemPlaceable("food.pumpkin_pie", 16535, Block.pumpkinPie)).setMaxStackSize(1);
 
 
     public static int highestItemId = 0;
diff --git a/src/main/java/net/minecraft/core/item/ItemFood.java b/src/main/java/net/minecraft/core/item/ItemFood.java
index 81b46345a..2868deb76 100644
--- a/src/main/java/net/minecraft/core/item/ItemFood.java
+++ b/src/main/java/net/minecraft/core/item/ItemFood.java
@@ -22,7 +22,9 @@ public class ItemFood extends Item
     @Override
     public ItemStack onItemRightClick(ItemStack itemstack, World world, EntityPlayer entityplayer)
     {
-        if(entityplayer.getHealth() < entityplayer.getMaxHealth() && itemstack.consumeItem(entityplayer)) {
+        if(entityplayer.getHealth() < entityplayer.getMaxHealth()
+                && entityplayer.getHealth() + entityplayer.getTotalHealingRemaining() < entityplayer.getMaxHealth()
+                && itemstack.consumeItem(entityplayer)) {
             entityplayer.eatFood(this);
         }
         return itemstack;
diff --git a/src/main/java/net/minecraft/core/item/ItemRope.java b/src/main/java/net/minecraft/core/item/ItemRope.java
new file mode 100644
index 000000000..14b410cda
--- /dev/null
+++ b/src/main/java/net/minecraft/core/item/ItemRope.java
@@ -0,0 +1,50 @@
+package net.minecraft.core.item;
+
+import net.minecraft.core.block.Block;
+import net.minecraft.core.entity.player.EntityPlayer;
+import net.minecraft.core.enums.EnumBlockSoundEffectType;
+import net.minecraft.core.util.helper.Side;
+import net.minecraft.core.world.World;
+
+public class ItemRope extends ItemPlaceable{
+    public ItemRope(String name, int id, Block blockToPlace) {
+        super(name, id, blockToPlace);
+    }
+    @Override
+    public boolean onItemUse(ItemStack stack, EntityPlayer player, World world, int blockX, int blockY, int blockZ, Side side, double xPlaced, double yPlaced) {
+        if(stack.stackSize <= 0) {
+            return false;
+        }
+        boolean placeOnSide = true;
+        if (world.getBlock(blockX, blockY, blockZ) == blockToPlace && !player.isSneaking()){
+            placeOnSide = false;
+            int _y = blockY;
+            while (_y > 0){
+                _y--;
+                if (world.canBlockBePlacedAt(blockToPlace.id, blockX, _y, blockZ, false, side)){
+                    blockY = _y;
+                    break;
+                } else if (world.getBlock(blockX, _y, blockZ) != blockToPlace) {
+                    break;
+                }
+            }
+
+        }
+        if(!world.canPlaceInsideBlock(blockX, blockY, blockZ)) {
+            blockX += side.getOffsetX();
+            blockY += side.getOffsetY();
+            blockZ += side.getOffsetZ();
+        }
+        if(blockY < 0 || blockY >= world.getHeightBlocks()) {
+            return false;
+        }
+        if(world.canBlockBePlacedAt(blockToPlace.id, blockX, blockY, blockZ, false, side) && stack.consumeItem(player)) {
+            if(world.setBlockAndMetadataWithNotify(blockX, blockY, blockZ, blockToPlace.id, placeOnSide ? 0b1000_0000 : 0)) {
+                blockToPlace.onBlockPlaced(world, blockX, blockY, blockZ, side, player, yPlaced);
+                world.playBlockSoundEffect(player, blockX + 0.5F, blockY + 0.5F, blockZ + 0.5F, blockToPlace, EnumBlockSoundEffectType.PLACE);
+            }
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/src/main/java/net/minecraft/core/net/command/Commands.java b/src/main/java/net/minecraft/core/net/command/Commands.java
index ee57ac78d..1d80ffa80 100644
--- a/src/main/java/net/minecraft/core/net/command/Commands.java
+++ b/src/main/java/net/minecraft/core/net/command/Commands.java
@@ -1,36 +1,7 @@
 package net.minecraft.core.net.command;
 
 import net.minecraft.client.Minecraft;
-import net.minecraft.core.net.command.commands.BiomeCommand;
-import net.minecraft.core.net.command.commands.ChunkCommand;
-import net.minecraft.core.net.command.commands.ClearCommand;
-import net.minecraft.core.net.command.commands.ColorCommand;
-import net.minecraft.core.net.command.commands.DeopCommand;
-import net.minecraft.core.net.command.commands.DifficultyCommand;
-import net.minecraft.core.net.command.commands.EmotesCommand;
-import net.minecraft.core.net.command.commands.GamemodeCommand;
-import net.minecraft.core.net.command.commands.GameruleCommand;
-import net.minecraft.core.net.command.commands.GenerateCommand;
-import net.minecraft.core.net.command.commands.GiveCommand;
-import net.minecraft.core.net.command.commands.HelpCommand;
-import net.minecraft.core.net.command.commands.KillCommand;
-import net.minecraft.core.net.command.commands.ListCommand;
-import net.minecraft.core.net.command.commands.NicknameCommand;
-import net.minecraft.core.net.command.commands.OpCommand;
-import net.minecraft.core.net.command.commands.PlaySoundCommand;
-import net.minecraft.core.net.command.commands.ScoreCommand;
-import net.minecraft.core.net.command.commands.SeedCommand;
-import net.minecraft.core.net.command.commands.SetBlockCommand;
-import net.minecraft.core.net.command.commands.SetSpawnCommand;
-import net.minecraft.core.net.command.commands.SpawnCommand;
-import net.minecraft.core.net.command.commands.SpawnParticleCommand;
-import net.minecraft.core.net.command.commands.StopCommand;
-import net.minecraft.core.net.command.commands.SummonCommand;
-import net.minecraft.core.net.command.commands.TeleportCommand;
-import net.minecraft.core.net.command.commands.TimeCommand;
-import net.minecraft.core.net.command.commands.WeatherCommand;
-import net.minecraft.core.net.command.commands.WhisperCommand;
-import net.minecraft.core.net.command.commands.WhoisCommand;
+import net.minecraft.core.net.command.commands.*;
 import net.minecraft.server.MinecraftServer;
 
 import java.util.ArrayList;
@@ -63,6 +34,7 @@ public final class Commands {
 		commands.add(new BiomeCommand());
 		commands.add(new SpawnParticleCommand());
 		commands.add(new PlaySoundCommand());
+		commands.add(new HarmCommand());
 	}
 	
 	public static void initServerCommands(MinecraftServer server) {
diff --git a/src/main/java/net/minecraft/core/net/command/commands/HarmCommand.java b/src/main/java/net/minecraft/core/net/command/commands/HarmCommand.java
new file mode 100644
index 000000000..a2a21d812
--- /dev/null
+++ b/src/main/java/net/minecraft/core/net/command/commands/HarmCommand.java
@@ -0,0 +1,68 @@
+package net.minecraft.core.net.command.commands;
+
+import net.minecraft.core.entity.player.EntityPlayer;
+import net.minecraft.core.net.command.Command;
+import net.minecraft.core.net.command.CommandError;
+import net.minecraft.core.net.command.CommandHandler;
+import net.minecraft.core.net.command.CommandSender;
+import net.minecraft.core.util.helper.DamageType;
+
+public class HarmCommand extends Command
+{
+    public HarmCommand() {
+        super("harm");
+    }
+
+    @Override
+    public boolean execute(CommandHandler handler, CommandSender sender, String[] args)
+    {
+        if (args.length == 0)
+        {
+            EntityPlayer player = sender.getPlayer();
+            player.hurt(player, 1, DamageType.GENERIC);
+
+            sender.sendMessage("Harmed player " + player.getDisplayName() + "for 1");
+            return true;
+        }
+        else if (args.length == 1)
+        {
+            EntityPlayer player = handler.getPlayer(args[0]);
+            if (player == null) return false;
+
+            player.hurt(player, 1, DamageType.GENERIC);
+            sender.sendMessage("Harmed player " + player.getDisplayName() + "for 1");
+            return true;
+        }
+        else if (args.length == 2)
+        {
+            EntityPlayer player = handler.getPlayer(args[0]);
+            int damageAmount = parseInt(args[1]);
+            if (player == null) return false;
+
+            player.hurt(player, damageAmount, DamageType.GENERIC);
+            sender.sendMessage("Harmed player " + player.getDisplayName() + "for " + damageAmount);
+            return true;
+        }
+
+        return false;
+    }
+
+    public int parseInt(String str) {
+        try {
+            return Integer.parseInt(str);
+        }catch (Exception e) {
+            throw new CommandError("Not an integer: \""+str+"\"");
+        }
+    }
+
+    @Override
+    public boolean opRequired(String[] args) {
+        return true;
+    }
+
+    @Override
+    public void sendCommandSyntax(CommandHandler handler, CommandSender sender) {
+        sender.sendMessage("/harm");
+        sender.sendMessage("/harm <username> <amount>");
+    }
+}
diff --git a/src/main/java/net/minecraft/core/sound/BlockSoundDispatcher.java b/src/main/java/net/minecraft/core/sound/BlockSoundDispatcher.java
index 8eff832af..36916fe64 100644
--- a/src/main/java/net/minecraft/core/sound/BlockSoundDispatcher.java
+++ b/src/main/java/net/minecraft/core/sound/BlockSoundDispatcher.java
@@ -1 +1 @@
-package net.minecraft.core.sound;

import net.minecraft.client.util.dispatch.Dispatcher;
import net.minecraft.core.block.Block;

public class BlockSoundDispatcher
    extends Dispatcher<Block, BlockSound>
{
    private static final BlockSoundDispatcher instance = new BlockSoundDispatcher();

    public static BlockSoundDispatcher getInstance()
    {
        return instance;
    }

    private BlockSoundDispatcher()
    {
        addDispatch(Block.stone, BlockSounds.STONE);
        addDispatch(Block.basalt, BlockSounds.STONE);
        addDispatch(Block.limestone, BlockSounds.STONE);
        addDispatch(Block.granite, BlockSounds.STONE);
        addDispatch(Block.marble, BlockSounds.STONE);
        addDispatch(Block.slate, BlockSounds.STONE);
        addDispatch(Block.permafrost, BlockSounds.STONE);

        addDispatch(Block.cobbleStone, BlockSounds.STONE);
        addDispatch(Block.cobbleStoneMossy, BlockSounds.STONE);
        addDispatch(Block.cobbleBasalt, BlockSounds.STONE);
        addDispatch(Block.cobbleLimestone, BlockSounds.STONE);
        addDispatch(Block.cobbleGranite, BlockSounds.STONE);
        addDispatch(Block.cobblePermafrost, BlockSounds.STONE);

        addDispatch(Block.stonePolished, BlockSounds.STONE);
        addDispatch(Block.granitePolished, BlockSounds.STONE);
        addDispatch(Block.limestonePolished, BlockSounds.STONE);
        addDispatch(Block.basaltPolished, BlockSounds.STONE);
        addDispatch(Block.slatePolished, BlockSounds.STONE);

        addDispatch(Block.pillarMarble, BlockSounds.STONE);
        addDispatch(Block.capstoneMarble, BlockSounds.STONE);

        addDispatch(Block.sandstone, BlockSounds.STONE);

        addDispatch(Block.stoneCarved, BlockSounds.STONE);
        addDispatch(Block.graniteCarved, BlockSounds.STONE);
        addDispatch(Block.limestoneCarved, BlockSounds.STONE);
        addDispatch(Block.basaltCarved, BlockSounds.STONE);

        addDispatch(Block.planksOak, BlockSounds.WOOD);
        addDispatch(Block.planksOakPainted, BlockSounds.WOOD);

        addDispatch(Block.torchCoal, BlockSounds.WOOD);
//        addDispatch(Block.candleSoulwax, BlockSounds.CLOTH);

        addDispatch(Block.ladderOak, BlockSounds.WOOD);

        addDispatch(Block.fencePlanksOak, BlockSounds.WOOD);
        addDispatch(Block.fencePlanksOakPainted, BlockSounds.WOOD);

        addDispatch(Block.fencegatePlanksOak, BlockSounds.WOOD);
        addDispatch(Block.fencegatePlanksOakPainted, BlockSounds.WOOD);

        addDispatch(Block.bookshelfPlanksOak, BlockSounds.WOOD);

        addDispatch(Block.wool, BlockSounds.CLOTH);
        addDispatch(Block.rope, BlockSounds.CLOTH);

        addDispatch(Block.brickClay, BlockSounds.STONE);
        addDispatch(Block.brickStonePolished, BlockSounds.STONE);
        addDispatch(Block.brickStonePolishedMossy, BlockSounds.STONE);
        addDispatch(Block.brickSandstone, BlockSounds.STONE);
        addDispatch(Block.brickGold, BlockSounds.METAL);
        addDispatch(Block.brickLapis, BlockSounds.STONE);
        addDispatch(Block.brickBasalt, BlockSounds.STONE);
        addDispatch(Block.brickLimestone, BlockSounds.STONE);
        addDispatch(Block.brickGranite, BlockSounds.STONE);
        addDispatch(Block.brickMarble, BlockSounds.STONE);
        addDispatch(Block.brickSlate, BlockSounds.STONE);
        addDispatch(Block.brickStone, BlockSounds.STONE);
        addDispatch(Block.brickPermafrost, BlockSounds.STONE);
        addDispatch(Block.brickIron, BlockSounds.METAL);

        addDispatch(Block.slabPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.slabCobbleStone, BlockSounds.STONE);
        addDispatch(Block.slabSandstone, BlockSounds.STONE);
        addDispatch(Block.slabBrickStonePolished, BlockSounds.STONE);
        addDispatch(Block.slabStonePolished, BlockSounds.STONE);
        addDispatch(Block.slabBrickMarble, BlockSounds.STONE);
        addDispatch(Block.slabBrickClay, BlockSounds.STONE);
        addDispatch(Block.slabCapstoneMarble, BlockSounds.STONE);
        addDispatch(Block.slabCobbleBasalt, BlockSounds.STONE);
        addDispatch(Block.slabCobbleLimestone, BlockSounds.STONE);
        addDispatch(Block.slabCobbleGranite, BlockSounds.STONE);
        addDispatch(Block.slabBrickBasalt, BlockSounds.STONE);
        addDispatch(Block.slabBrickLimestone, BlockSounds.STONE);
        addDispatch(Block.slabBrickGranite, BlockSounds.STONE);
        addDispatch(Block.slabPlanksOakPainted, BlockSounds.WOOD);
        addDispatch(Block.slabBrickSlate, BlockSounds.STONE);
        addDispatch(Block.slabBrickStone, BlockSounds.STONE);
        addDispatch(Block.slabGranitePolished, BlockSounds.STONE);
        addDispatch(Block.slabLimestonePolished, BlockSounds.STONE);
        addDispatch(Block.slabBasaltPolished, BlockSounds.STONE);

        addDispatch(Block.stairsPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.stairsCobbleStone, BlockSounds.STONE);
        addDispatch(Block.stairsBrickStonePolished, BlockSounds.STONE);
        addDispatch(Block.stairsBrickMarble, BlockSounds.STONE);
        addDispatch(Block.stairsCobbleBasalt, BlockSounds.STONE);
        addDispatch(Block.stairsCobbleLimestone, BlockSounds.STONE);
        addDispatch(Block.stairsCobbleGranite, BlockSounds.STONE);
        addDispatch(Block.stairsBrickBasalt, BlockSounds.STONE);
        addDispatch(Block.stairsBrickLimestone, BlockSounds.STONE);
        addDispatch(Block.stairsBrickGranite, BlockSounds.STONE);
        addDispatch(Block.stairsBrickClay, BlockSounds.STONE);
        addDispatch(Block.stairsPlanksOakPainted, BlockSounds.WOOD);
        addDispatch(Block.stairsBrickSlate, BlockSounds.STONE);
        addDispatch(Block.stairsBrickStone, BlockSounds.STONE);

        addDispatch(Block.obsidian, BlockSounds.STONE);

        addDispatch(Block.glass, BlockSounds.GLASS);
        addDispatch(Block.glassTinted, BlockSounds.GLASS);

        addDispatch(Block.grass, BlockSounds.GRASS);
        addDispatch(Block.grassRetro, BlockSounds.GRASS);
        addDispatch(Block.grassScorched, BlockSounds.GRASS);

        addDispatch(Block.pathDirt, BlockSounds.GRAVEL);

        addDispatch(Block.dirt, BlockSounds.GRAVEL);
        addDispatch(Block.dirtScorched, BlockSounds.GRAVEL);
        addDispatch(Block.dirtScorchedRich, BlockSounds.GRAVEL);

        addDispatch(Block.mud, BlockSounds.GRAVEL);
        addDispatch(Block.mudBaked, BlockSounds.STONE);

        addDispatch(Block.spongeDry, BlockSounds.GRASS);
        addDispatch(Block.spongeWet, BlockSounds.GRASS);

        addDispatch(Block.mossStone, BlockSounds.GRASS);
        addDispatch(Block.mossBasalt, BlockSounds.GRASS);
        addDispatch(Block.mossLimestone, BlockSounds.GRASS);
        addDispatch(Block.mossGranite, BlockSounds.GRASS);

        addDispatch(Block.sand, BlockSounds.SAND);
        addDispatch(Block.gravel, BlockSounds.GRAVEL);

        addDispatch(Block.bedrock, BlockSounds.STONE);

        addDispatch(Block.fluidWaterFlowing, BlockSounds.DEFAULT);
        addDispatch(Block.fluidWaterStill, BlockSounds.DEFAULT);
        addDispatch(Block.fluidLavaFlowing, BlockSounds.DEFAULT);
        addDispatch(Block.fluidLavaStill, BlockSounds.DEFAULT);

        addDispatch(Block.logOak, BlockSounds.WOOD);
        addDispatch(Block.logPine, BlockSounds.WOOD);
        addDispatch(Block.logBirch, BlockSounds.WOOD);
        addDispatch(Block.logCherry, BlockSounds.WOOD);
        addDispatch(Block.logEucalyptus, BlockSounds.WOOD);
        addDispatch(Block.logOakMossy, BlockSounds.WOOD);

        addDispatch(Block.leavesOak, BlockSounds.GRASS);
        addDispatch(Block.leavesOakRetro, BlockSounds.GRASS);
        addDispatch(Block.leavesPine, BlockSounds.GRASS);
        addDispatch(Block.leavesBirch, BlockSounds.GRASS);
        addDispatch(Block.leavesCherry, BlockSounds.GRASS);
        addDispatch(Block.leavesEucalyptus, BlockSounds.GRASS);
        addDispatch(Block.leavesShrub, BlockSounds.GRASS);
        addDispatch(Block.leavesCherryFlowering, BlockSounds.GRASS);
        addDispatch(Block.leavesCacao, BlockSounds.GRASS);
        addDispatch(Block.leavesCaatinga, BlockSounds.GRASS);

        addDispatch(Block.saplingOak, BlockSounds.GRASS);
        addDispatch(Block.saplingOakRetro, BlockSounds.GRASS);
        addDispatch(Block.saplingPine, BlockSounds.GRASS);
        addDispatch(Block.saplingBirch, BlockSounds.GRASS);
        addDispatch(Block.saplingCherry, BlockSounds.GRASS);
        addDispatch(Block.saplingEucalyptus, BlockSounds.GRASS);
        addDispatch(Block.saplingShrub, BlockSounds.GRASS);
        addDispatch(Block.saplingCacao, BlockSounds.GRASS);

        addDispatch(Block.tallgrass, BlockSounds.GRASS);
        addDispatch(Block.tallgrassFern, BlockSounds.GRASS);
        addDispatch(Block.deadbush, BlockSounds.GRASS);
        addDispatch(Block.spinifex, BlockSounds.GRASS);
        addDispatch(Block.algae, BlockSounds.GRASS);

        addDispatch(Block.flowerYellow, BlockSounds.GRASS);
        addDispatch(Block.flowerRed, BlockSounds.GRASS);

        addDispatch(Block.flowerPurple, BlockSounds.GRASS);
        addDispatch(Block.flowerPink, BlockSounds.GRASS);
        addDispatch(Block.flowerLightBlue, BlockSounds.GRASS);

        addDispatch(Block.mushroomBrown, BlockSounds.GRASS);
        addDispatch(Block.mushroomRed, BlockSounds.GRASS);

        addDispatch(Block.oreCoalStone, BlockSounds.STONE);
        addDispatch(Block.oreCoalBasalt, BlockSounds.STONE);
        addDispatch(Block.oreCoalLimestone, BlockSounds.STONE);
        addDispatch(Block.oreCoalGranite, BlockSounds.STONE);

        addDispatch(Block.oreIronStone, BlockSounds.STONE);
        addDispatch(Block.oreIronBasalt, BlockSounds.STONE);
        addDispatch(Block.oreIronLimestone, BlockSounds.STONE);
        addDispatch(Block.oreIronGranite, BlockSounds.STONE);

        addDispatch(Block.oreGoldStone, BlockSounds.STONE);
        addDispatch(Block.oreGoldBasalt, BlockSounds.STONE);
        addDispatch(Block.oreGoldLimestone, BlockSounds.STONE);
        addDispatch(Block.oreGoldGranite, BlockSounds.STONE);

        addDispatch(Block.oreLapisStone, BlockSounds.STONE);
        addDispatch(Block.oreLapisBasalt, BlockSounds.STONE);
        addDispatch(Block.oreLapisLimestone, BlockSounds.STONE);
        addDispatch(Block.oreLapisGranite, BlockSounds.STONE);

        addDispatch(Block.oreRedstoneStone, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneBasalt, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneLimestone, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneGranite, BlockSounds.STONE);

        addDispatch(Block.oreRedstoneGlowingStone, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneGlowingBasalt, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneGlowingLimestone, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneGlowingGranite, BlockSounds.STONE);

        addDispatch(Block.oreDiamondStone, BlockSounds.STONE);
        addDispatch(Block.oreDiamondBasalt, BlockSounds.STONE);
        addDispatch(Block.oreDiamondLimestone, BlockSounds.STONE);
        addDispatch(Block.oreDiamondGranite, BlockSounds.STONE);

        addDispatch(Block.oreNethercoalNetherrack, BlockSounds.STONE);

        addDispatch(Block.blockCoal, BlockSounds.STONE);
        addDispatch(Block.blockIron, BlockSounds.METAL);
        addDispatch(Block.blockGold, BlockSounds.METAL);
        addDispatch(Block.blockLapis, BlockSounds.STONE);
        addDispatch(Block.blockRedstone, BlockSounds.STONE);
        addDispatch(Block.blockDiamond, BlockSounds.STONE);
        addDispatch(Block.blockNetherCoal, BlockSounds.STONE);
        addDispatch(Block.blockSteel, BlockSounds.METAL);
        addDispatch(Block.blockQuartz, BlockSounds.STONE);
        addDispatch(Block.blockOlivine, BlockSounds.STONE);
        addDispatch(Block.blockCharcoal, BlockSounds.STONE);

        addDispatch(Block.wireRedstone, BlockSounds.STONE);

        addDispatch(Block.torchRedstoneIdle, BlockSounds.WOOD);
        addDispatch(Block.torchRedstoneActive, BlockSounds.WOOD);

        addDispatch(Block.buttonStone, BlockSounds.STONE);

        addDispatch(Block.leverCobbleStone, BlockSounds.STONE);

        addDispatch(Block.pressureplateStone, BlockSounds.STONE);
        addDispatch(Block.pressureplatePlanksOak, BlockSounds.WOOD);
        addDispatch(Block.pressureplateCobbleStone, BlockSounds.STONE);

        addDispatch(Block.motionsensorIdle, BlockSounds.STONE);
        addDispatch(Block.motionsensorActive, BlockSounds.STONE);

        addDispatch(Block.repeaterIdle, BlockSounds.STONE);
        addDispatch(Block.repeaterActive, BlockSounds.STONE);

        addDispatch(Block.pistonBase, BlockSounds.STONE);
        addDispatch(Block.pistonBaseSticky, BlockSounds.STONE);
        addDispatch(Block.pistonHead, BlockSounds.STONE);
        addDispatch(Block.pistonMoving, BlockSounds.STONE);

        addDispatch(Block.noteblock, BlockSounds.WOOD);

        addDispatch(Block.rail, BlockSounds.METAL);
        addDispatch(Block.railPowered, BlockSounds.METAL);
        addDispatch(Block.railDetector, BlockSounds.METAL);

        addDispatch(Block.spikes, BlockSounds.METAL);

        addDispatch(Block.dispenserCobbleStone, BlockSounds.STONE);

        addDispatch(Block.trapdoorPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.trapdoorPlanksOakPainted, BlockSounds.WOOD);
        addDispatch(Block.trapdoorIron, BlockSounds.METAL);
        addDispatch(Block.trapdoorGlass, BlockSounds.GLASS);

        addDispatch(Block.tnt, BlockSounds.GRASS);

        addDispatch(Block.doorPlanksOakBottom, BlockSounds.WOOD);
        addDispatch(Block.doorPlanksOakTop, BlockSounds.WOOD);
        addDispatch(Block.doorIronBottom, BlockSounds.METAL);
        addDispatch(Block.doorIronTop, BlockSounds.METAL);
        addDispatch(Block.doorPlanksOakPaintedBottom, BlockSounds.WOOD);
        addDispatch(Block.doorPlanksOakPaintedTop, BlockSounds.WOOD);
        addDispatch(Block.doorGlassBottom, BlockSounds.GLASS);
        addDispatch(Block.doorGlassTop, BlockSounds.GLASS);

        addDispatch(Block.mesh, BlockSounds.METAL);
        addDispatch(Block.meshGold, BlockSounds.METAL);

        addDispatch(Block.bed, BlockSounds.WOOD);
        addDispatch(Block.seat, BlockSounds.WOOD);

        addDispatch(Block.cobweb, BlockSounds.CLOTH);

        addDispatch(Block.fire, BlockSounds.FIRE);
        addDispatch(Block.brazierInactive, BlockSounds.METAL);
        addDispatch(Block.brazierActive, BlockSounds.FIRE);

        addDispatch(Block.mobspawner, BlockSounds.METAL);
        addDispatch(Block.mobspawnerDeactivated, BlockSounds.METAL);

        addDispatch(Block.workbench, BlockSounds.WOOD);

        addDispatch(Block.furnaceStoneIdle, BlockSounds.STONE);
        addDispatch(Block.furnaceStoneActive, BlockSounds.STONE);
        addDispatch(Block.furnaceBlastIdle, BlockSounds.METAL);
        addDispatch(Block.furnaceBlastActive, BlockSounds.METAL);

        addDispatch(Block.trommelIdle, BlockSounds.STONE);
        addDispatch(Block.trommelActive, BlockSounds.STONE);

        addDispatch(Block.chestLegacy, BlockSounds.WOOD);
        addDispatch(Block.chestLegacyPainted, BlockSounds.WOOD);
        addDispatch(Block.chestPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.chestPlanksOakPainted, BlockSounds.WOOD);

        addDispatch(Block.basket, BlockSounds.CLOTH);

        addDispatch(Block.cropsWheat, BlockSounds.GRASS);
        addDispatch(Block.cropsPumpkin, BlockSounds.WOOD);

        addDispatch(Block.farmlandDirt, BlockSounds.GRAVEL);

        addDispatch(Block.signPostPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.signWallPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.flag, BlockSounds.WOOD);

        addDispatch(Block.layerSnow, BlockSounds.CLOTH);
        addDispatch(Block.layerLeavesOak, BlockSounds.GRASS);
        addDispatch(Block.layerSlate, BlockSounds.STONE);

        addDispatch(Block.ice, BlockSounds.GLASS);
        addDispatch(Block.permaice, BlockSounds.GLASS);

        addDispatch(Block.blockSnow, BlockSounds.CLOTH);

        addDispatch(Block.cactus, BlockSounds.CLOTH);

        addDispatch(Block.blockClay, BlockSounds.GRAVEL);

        addDispatch(Block.sugarcane, BlockSounds.GRASS);
        addDispatch(Block.blockSugarcane, BlockSounds.GRASS);
        addDispatch(Block.blockSugarcaneBaked, BlockSounds.GRASS);

        addDispatch(Block.jukebox, BlockSounds.WOOD);

        addDispatch(Block.pumpkin, BlockSounds.WOOD);
        addDispatch(Block.pumpkinCarvedIdle, BlockSounds.WOOD);
        addDispatch(Block.pumpkinCarvedActive, BlockSounds.WOOD);

        addDispatch(Block.netherrack, BlockSounds.STONE);
        addDispatch(Block.netherrackIgneous, BlockSounds.STONE);

        addDispatch(Block.soulsand, BlockSounds.SAND);

        addDispatch(Block.glowstone, BlockSounds.GLASS);

        addDispatch(Block.portalNether, BlockSounds.GLASS);
        addDispatch(Block.portalParadise, BlockSounds.GLASS);

        addDispatch(Block.cake, BlockSounds.CLOTH);

        addDispatch(Block.lampIdle, BlockSounds.GLASS);
        addDispatch(Block.lampActive, BlockSounds.GLASS);

        addDispatch(Block.lanternFireflyGreen, BlockSounds.GLASS);
        addDispatch(Block.lanternFireflyBlue, BlockSounds.GLASS);
        addDispatch(Block.lanternFireflyOrange, BlockSounds.GLASS);
        addDispatch(Block.lanternFireflyRed, BlockSounds.GLASS);
        addDispatch(Block.jarGlass, BlockSounds.GLASS);

        addDispatch(Block.overlayPebbles, BlockSounds.STONE);

        addDispatch(Block.fenceChainlink, BlockSounds.METAL);
        addDispatch(Block.fencePaperWall, BlockSounds.CLOTH);
        addDispatch(Block.paperWall, BlockSounds.CLOTH);

        validate();
    }

    @Override
    protected BlockSound getDefault()
    {
        return BlockSounds.DEFAULT;
    }

    private void validate()
    {
        for (Block block : Block.blocksList)
        {
            if (block != null && dispatches.get(block) == null)
            {
                throw new RuntimeException("Block " + block.getKey() + " has no assigned sound!");
            }
        }
    }
}
\ No newline at end of file
+package net.minecraft.core.sound;

import net.minecraft.client.util.dispatch.Dispatcher;
import net.minecraft.core.block.Block;

public class BlockSoundDispatcher
    extends Dispatcher<Block, BlockSound>
{
    private static final BlockSoundDispatcher instance = new BlockSoundDispatcher();

    public static BlockSoundDispatcher getInstance()
    {
        return instance;
    }

    private BlockSoundDispatcher()
    {
        addDispatch(Block.stone, BlockSounds.STONE);
        addDispatch(Block.basalt, BlockSounds.STONE);
        addDispatch(Block.limestone, BlockSounds.STONE);
        addDispatch(Block.granite, BlockSounds.STONE);
        addDispatch(Block.marble, BlockSounds.STONE);
        addDispatch(Block.slate, BlockSounds.STONE);
        addDispatch(Block.permafrost, BlockSounds.STONE);

        addDispatch(Block.cobbleStone, BlockSounds.STONE);
        addDispatch(Block.cobbleStoneMossy, BlockSounds.STONE);
        addDispatch(Block.cobbleBasalt, BlockSounds.STONE);
        addDispatch(Block.cobbleLimestone, BlockSounds.STONE);
        addDispatch(Block.cobbleGranite, BlockSounds.STONE);
        addDispatch(Block.cobblePermafrost, BlockSounds.STONE);

        addDispatch(Block.stonePolished, BlockSounds.STONE);
        addDispatch(Block.granitePolished, BlockSounds.STONE);
        addDispatch(Block.limestonePolished, BlockSounds.STONE);
        addDispatch(Block.basaltPolished, BlockSounds.STONE);
        addDispatch(Block.slatePolished, BlockSounds.STONE);

        addDispatch(Block.pillarMarble, BlockSounds.STONE);
        addDispatch(Block.capstoneMarble, BlockSounds.STONE);

        addDispatch(Block.sandstone, BlockSounds.STONE);

        addDispatch(Block.stoneCarved, BlockSounds.STONE);
        addDispatch(Block.graniteCarved, BlockSounds.STONE);
        addDispatch(Block.limestoneCarved, BlockSounds.STONE);
        addDispatch(Block.basaltCarved, BlockSounds.STONE);

        addDispatch(Block.planksOak, BlockSounds.WOOD);
        addDispatch(Block.planksOakPainted, BlockSounds.WOOD);

        addDispatch(Block.torchCoal, BlockSounds.WOOD);
//        addDispatch(Block.candleSoulwax, BlockSounds.CLOTH);

        addDispatch(Block.ladderOak, BlockSounds.WOOD);

        addDispatch(Block.fencePlanksOak, BlockSounds.WOOD);
        addDispatch(Block.fencePlanksOakPainted, BlockSounds.WOOD);

        addDispatch(Block.fencegatePlanksOak, BlockSounds.WOOD);
        addDispatch(Block.fencegatePlanksOakPainted, BlockSounds.WOOD);

        addDispatch(Block.bookshelfPlanksOak, BlockSounds.WOOD);

        addDispatch(Block.wool, BlockSounds.CLOTH);
        addDispatch(Block.rope, BlockSounds.CLOTH);

        addDispatch(Block.brickClay, BlockSounds.STONE);
        addDispatch(Block.brickStonePolished, BlockSounds.STONE);
        addDispatch(Block.brickStonePolishedMossy, BlockSounds.STONE);
        addDispatch(Block.brickSandstone, BlockSounds.STONE);
        addDispatch(Block.brickGold, BlockSounds.METAL);
        addDispatch(Block.brickLapis, BlockSounds.STONE);
        addDispatch(Block.brickBasalt, BlockSounds.STONE);
        addDispatch(Block.brickLimestone, BlockSounds.STONE);
        addDispatch(Block.brickGranite, BlockSounds.STONE);
        addDispatch(Block.brickMarble, BlockSounds.STONE);
        addDispatch(Block.brickSlate, BlockSounds.STONE);
        addDispatch(Block.brickStone, BlockSounds.STONE);
        addDispatch(Block.brickPermafrost, BlockSounds.STONE);
        addDispatch(Block.brickIron, BlockSounds.METAL);

        addDispatch(Block.slabPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.slabCobbleStone, BlockSounds.STONE);
        addDispatch(Block.slabSandstone, BlockSounds.STONE);
        addDispatch(Block.slabBrickStonePolished, BlockSounds.STONE);
        addDispatch(Block.slabStonePolished, BlockSounds.STONE);
        addDispatch(Block.slabBrickMarble, BlockSounds.STONE);
        addDispatch(Block.slabBrickClay, BlockSounds.STONE);
        addDispatch(Block.slabCapstoneMarble, BlockSounds.STONE);
        addDispatch(Block.slabCobbleBasalt, BlockSounds.STONE);
        addDispatch(Block.slabCobbleLimestone, BlockSounds.STONE);
        addDispatch(Block.slabCobbleGranite, BlockSounds.STONE);
        addDispatch(Block.slabBrickBasalt, BlockSounds.STONE);
        addDispatch(Block.slabBrickLimestone, BlockSounds.STONE);
        addDispatch(Block.slabBrickGranite, BlockSounds.STONE);
        addDispatch(Block.slabPlanksOakPainted, BlockSounds.WOOD);
        addDispatch(Block.slabBrickSlate, BlockSounds.STONE);
        addDispatch(Block.slabBrickStone, BlockSounds.STONE);
        addDispatch(Block.slabGranitePolished, BlockSounds.STONE);
        addDispatch(Block.slabLimestonePolished, BlockSounds.STONE);
        addDispatch(Block.slabBasaltPolished, BlockSounds.STONE);

        addDispatch(Block.stairsPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.stairsCobbleStone, BlockSounds.STONE);
        addDispatch(Block.stairsBrickStonePolished, BlockSounds.STONE);
        addDispatch(Block.stairsBrickMarble, BlockSounds.STONE);
        addDispatch(Block.stairsCobbleBasalt, BlockSounds.STONE);
        addDispatch(Block.stairsCobbleLimestone, BlockSounds.STONE);
        addDispatch(Block.stairsCobbleGranite, BlockSounds.STONE);
        addDispatch(Block.stairsBrickBasalt, BlockSounds.STONE);
        addDispatch(Block.stairsBrickLimestone, BlockSounds.STONE);
        addDispatch(Block.stairsBrickGranite, BlockSounds.STONE);
        addDispatch(Block.stairsBrickClay, BlockSounds.STONE);
        addDispatch(Block.stairsPlanksOakPainted, BlockSounds.WOOD);
        addDispatch(Block.stairsBrickSlate, BlockSounds.STONE);
        addDispatch(Block.stairsBrickStone, BlockSounds.STONE);

        addDispatch(Block.obsidian, BlockSounds.STONE);

        addDispatch(Block.glass, BlockSounds.GLASS);
        addDispatch(Block.glassTinted, BlockSounds.GLASS);

        addDispatch(Block.grass, BlockSounds.GRASS);
        addDispatch(Block.grassRetro, BlockSounds.GRASS);
        addDispatch(Block.grassScorched, BlockSounds.GRASS);

        addDispatch(Block.pathDirt, BlockSounds.GRAVEL);

        addDispatch(Block.dirt, BlockSounds.GRAVEL);
        addDispatch(Block.dirtScorched, BlockSounds.GRAVEL);
        addDispatch(Block.dirtScorchedRich, BlockSounds.GRAVEL);

        addDispatch(Block.mud, BlockSounds.GRAVEL);
        addDispatch(Block.mudBaked, BlockSounds.STONE);

        addDispatch(Block.spongeDry, BlockSounds.GRASS);
        addDispatch(Block.spongeWet, BlockSounds.GRASS);

        addDispatch(Block.mossStone, BlockSounds.GRASS);
        addDispatch(Block.mossBasalt, BlockSounds.GRASS);
        addDispatch(Block.mossLimestone, BlockSounds.GRASS);
        addDispatch(Block.mossGranite, BlockSounds.GRASS);

        addDispatch(Block.sand, BlockSounds.SAND);
        addDispatch(Block.gravel, BlockSounds.GRAVEL);

        addDispatch(Block.bedrock, BlockSounds.STONE);

        addDispatch(Block.fluidWaterFlowing, BlockSounds.DEFAULT);
        addDispatch(Block.fluidWaterStill, BlockSounds.DEFAULT);
        addDispatch(Block.fluidLavaFlowing, BlockSounds.DEFAULT);
        addDispatch(Block.fluidLavaStill, BlockSounds.DEFAULT);

        addDispatch(Block.logOak, BlockSounds.WOOD);
        addDispatch(Block.logPine, BlockSounds.WOOD);
        addDispatch(Block.logBirch, BlockSounds.WOOD);
        addDispatch(Block.logCherry, BlockSounds.WOOD);
        addDispatch(Block.logEucalyptus, BlockSounds.WOOD);
        addDispatch(Block.logOakMossy, BlockSounds.WOOD);

        addDispatch(Block.leavesOak, BlockSounds.GRASS);
        addDispatch(Block.leavesOakRetro, BlockSounds.GRASS);
        addDispatch(Block.leavesPine, BlockSounds.GRASS);
        addDispatch(Block.leavesBirch, BlockSounds.GRASS);
        addDispatch(Block.leavesCherry, BlockSounds.GRASS);
        addDispatch(Block.leavesEucalyptus, BlockSounds.GRASS);
        addDispatch(Block.leavesShrub, BlockSounds.GRASS);
        addDispatch(Block.leavesCherryFlowering, BlockSounds.GRASS);
        addDispatch(Block.leavesCacao, BlockSounds.GRASS);
        addDispatch(Block.leavesCaatinga, BlockSounds.GRASS);

        addDispatch(Block.saplingOak, BlockSounds.GRASS);
        addDispatch(Block.saplingOakRetro, BlockSounds.GRASS);
        addDispatch(Block.saplingPine, BlockSounds.GRASS);
        addDispatch(Block.saplingBirch, BlockSounds.GRASS);
        addDispatch(Block.saplingCherry, BlockSounds.GRASS);
        addDispatch(Block.saplingEucalyptus, BlockSounds.GRASS);
        addDispatch(Block.saplingShrub, BlockSounds.GRASS);
        addDispatch(Block.saplingCacao, BlockSounds.GRASS);

        addDispatch(Block.tallgrass, BlockSounds.GRASS);
        addDispatch(Block.tallgrassFern, BlockSounds.GRASS);
        addDispatch(Block.deadbush, BlockSounds.GRASS);
        addDispatch(Block.spinifex, BlockSounds.GRASS);
        addDispatch(Block.algae, BlockSounds.GRASS);

        addDispatch(Block.flowerYellow, BlockSounds.GRASS);
        addDispatch(Block.flowerRed, BlockSounds.GRASS);

        addDispatch(Block.flowerPurple, BlockSounds.GRASS);
        addDispatch(Block.flowerPink, BlockSounds.GRASS);
        addDispatch(Block.flowerLightBlue, BlockSounds.GRASS);

        addDispatch(Block.mushroomBrown, BlockSounds.GRASS);
        addDispatch(Block.mushroomRed, BlockSounds.GRASS);

        addDispatch(Block.oreCoalStone, BlockSounds.STONE);
        addDispatch(Block.oreCoalBasalt, BlockSounds.STONE);
        addDispatch(Block.oreCoalLimestone, BlockSounds.STONE);
        addDispatch(Block.oreCoalGranite, BlockSounds.STONE);

        addDispatch(Block.oreIronStone, BlockSounds.STONE);
        addDispatch(Block.oreIronBasalt, BlockSounds.STONE);
        addDispatch(Block.oreIronLimestone, BlockSounds.STONE);
        addDispatch(Block.oreIronGranite, BlockSounds.STONE);

        addDispatch(Block.oreGoldStone, BlockSounds.STONE);
        addDispatch(Block.oreGoldBasalt, BlockSounds.STONE);
        addDispatch(Block.oreGoldLimestone, BlockSounds.STONE);
        addDispatch(Block.oreGoldGranite, BlockSounds.STONE);

        addDispatch(Block.oreLapisStone, BlockSounds.STONE);
        addDispatch(Block.oreLapisBasalt, BlockSounds.STONE);
        addDispatch(Block.oreLapisLimestone, BlockSounds.STONE);
        addDispatch(Block.oreLapisGranite, BlockSounds.STONE);

        addDispatch(Block.oreRedstoneStone, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneBasalt, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneLimestone, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneGranite, BlockSounds.STONE);

        addDispatch(Block.oreRedstoneGlowingStone, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneGlowingBasalt, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneGlowingLimestone, BlockSounds.STONE);
        addDispatch(Block.oreRedstoneGlowingGranite, BlockSounds.STONE);

        addDispatch(Block.oreDiamondStone, BlockSounds.STONE);
        addDispatch(Block.oreDiamondBasalt, BlockSounds.STONE);
        addDispatch(Block.oreDiamondLimestone, BlockSounds.STONE);
        addDispatch(Block.oreDiamondGranite, BlockSounds.STONE);

        addDispatch(Block.oreNethercoalNetherrack, BlockSounds.STONE);

        addDispatch(Block.blockCoal, BlockSounds.STONE);
        addDispatch(Block.blockIron, BlockSounds.METAL);
        addDispatch(Block.blockGold, BlockSounds.METAL);
        addDispatch(Block.blockLapis, BlockSounds.STONE);
        addDispatch(Block.blockRedstone, BlockSounds.STONE);
        addDispatch(Block.blockDiamond, BlockSounds.STONE);
        addDispatch(Block.blockNetherCoal, BlockSounds.STONE);
        addDispatch(Block.blockSteel, BlockSounds.METAL);
        addDispatch(Block.blockQuartz, BlockSounds.STONE);
        addDispatch(Block.blockOlivine, BlockSounds.STONE);
        addDispatch(Block.blockCharcoal, BlockSounds.STONE);

        addDispatch(Block.wireRedstone, BlockSounds.STONE);

        addDispatch(Block.torchRedstoneIdle, BlockSounds.WOOD);
        addDispatch(Block.torchRedstoneActive, BlockSounds.WOOD);

        addDispatch(Block.buttonStone, BlockSounds.STONE);

        addDispatch(Block.leverCobbleStone, BlockSounds.STONE);

        addDispatch(Block.pressureplateStone, BlockSounds.STONE);
        addDispatch(Block.pressureplatePlanksOak, BlockSounds.WOOD);
        addDispatch(Block.pressureplateCobbleStone, BlockSounds.STONE);

        addDispatch(Block.motionsensorIdle, BlockSounds.STONE);
        addDispatch(Block.motionsensorActive, BlockSounds.STONE);

        addDispatch(Block.repeaterIdle, BlockSounds.STONE);
        addDispatch(Block.repeaterActive, BlockSounds.STONE);

        addDispatch(Block.pistonBase, BlockSounds.STONE);
        addDispatch(Block.pistonBaseSticky, BlockSounds.STONE);
        addDispatch(Block.pistonHead, BlockSounds.STONE);
        addDispatch(Block.pistonMoving, BlockSounds.STONE);

        addDispatch(Block.noteblock, BlockSounds.WOOD);

        addDispatch(Block.rail, BlockSounds.METAL);
        addDispatch(Block.railPowered, BlockSounds.METAL);
        addDispatch(Block.railDetector, BlockSounds.METAL);

        addDispatch(Block.spikes, BlockSounds.METAL);

        addDispatch(Block.dispenserCobbleStone, BlockSounds.STONE);

        addDispatch(Block.trapdoorPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.trapdoorPlanksOakPainted, BlockSounds.WOOD);
        addDispatch(Block.trapdoorIron, BlockSounds.METAL);
        addDispatch(Block.trapdoorGlass, BlockSounds.GLASS);

        addDispatch(Block.tnt, BlockSounds.GRASS);

        addDispatch(Block.doorPlanksOakBottom, BlockSounds.WOOD);
        addDispatch(Block.doorPlanksOakTop, BlockSounds.WOOD);
        addDispatch(Block.doorIronBottom, BlockSounds.METAL);
        addDispatch(Block.doorIronTop, BlockSounds.METAL);
        addDispatch(Block.doorPlanksOakPaintedBottom, BlockSounds.WOOD);
        addDispatch(Block.doorPlanksOakPaintedTop, BlockSounds.WOOD);
        addDispatch(Block.doorGlassBottom, BlockSounds.GLASS);
        addDispatch(Block.doorGlassTop, BlockSounds.GLASS);

        addDispatch(Block.mesh, BlockSounds.METAL);
        addDispatch(Block.meshGold, BlockSounds.METAL);

        addDispatch(Block.bed, BlockSounds.WOOD);
        addDispatch(Block.seat, BlockSounds.WOOD);

        addDispatch(Block.cobweb, BlockSounds.CLOTH);

        addDispatch(Block.fire, BlockSounds.FIRE);
        addDispatch(Block.brazierInactive, BlockSounds.METAL);
        addDispatch(Block.brazierActive, BlockSounds.FIRE);

        addDispatch(Block.mobspawner, BlockSounds.METAL);
        addDispatch(Block.mobspawnerDeactivated, BlockSounds.METAL);

        addDispatch(Block.workbench, BlockSounds.WOOD);

        addDispatch(Block.furnaceStoneIdle, BlockSounds.STONE);
        addDispatch(Block.furnaceStoneActive, BlockSounds.STONE);
        addDispatch(Block.furnaceBlastIdle, BlockSounds.METAL);
        addDispatch(Block.furnaceBlastActive, BlockSounds.METAL);

        addDispatch(Block.trommelIdle, BlockSounds.STONE);
        addDispatch(Block.trommelActive, BlockSounds.STONE);

        addDispatch(Block.chestLegacy, BlockSounds.WOOD);
        addDispatch(Block.chestLegacyPainted, BlockSounds.WOOD);
        addDispatch(Block.chestPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.chestPlanksOakPainted, BlockSounds.WOOD);

        addDispatch(Block.basket, BlockSounds.CLOTH);

        addDispatch(Block.cropsWheat, BlockSounds.GRASS);
        addDispatch(Block.cropsPumpkin, BlockSounds.WOOD);

        addDispatch(Block.farmlandDirt, BlockSounds.GRAVEL);

        addDispatch(Block.signPostPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.signWallPlanksOak, BlockSounds.WOOD);
        addDispatch(Block.flag, BlockSounds.WOOD);

        addDispatch(Block.layerSnow, BlockSounds.CLOTH);
        addDispatch(Block.layerLeavesOak, BlockSounds.GRASS);
        addDispatch(Block.layerSlate, BlockSounds.STONE);

        addDispatch(Block.ice, BlockSounds.GLASS);
        addDispatch(Block.permaice, BlockSounds.GLASS);

        addDispatch(Block.blockSnow, BlockSounds.CLOTH);

        addDispatch(Block.cactus, BlockSounds.CLOTH);

        addDispatch(Block.blockClay, BlockSounds.GRAVEL);

        addDispatch(Block.sugarcane, BlockSounds.GRASS);
        addDispatch(Block.blockSugarcane, BlockSounds.GRASS);
        addDispatch(Block.blockSugarcaneBaked, BlockSounds.GRASS);

        addDispatch(Block.jukebox, BlockSounds.WOOD);

        addDispatch(Block.pumpkin, BlockSounds.WOOD);
        addDispatch(Block.pumpkinCarvedIdle, BlockSounds.WOOD);
        addDispatch(Block.pumpkinCarvedActive, BlockSounds.WOOD);

        addDispatch(Block.netherrack, BlockSounds.STONE);
        addDispatch(Block.netherrackIgneous, BlockSounds.STONE);

        addDispatch(Block.soulsand, BlockSounds.SAND);

        addDispatch(Block.glowstone, BlockSounds.GLASS);

        addDispatch(Block.portalNether, BlockSounds.GLASS);
        addDispatch(Block.portalParadise, BlockSounds.GLASS);

        addDispatch(Block.cake, BlockSounds.CLOTH);
        addDispatch(Block.pumpkinPie, BlockSounds.CLOTH);

        addDispatch(Block.lampIdle, BlockSounds.GLASS);
        addDispatch(Block.lampActive, BlockSounds.GLASS);

        addDispatch(Block.lanternFireflyGreen, BlockSounds.GLASS);
        addDispatch(Block.lanternFireflyBlue, BlockSounds.GLASS);
        addDispatch(Block.lanternFireflyOrange, BlockSounds.GLASS);
        addDispatch(Block.lanternFireflyRed, BlockSounds.GLASS);
        addDispatch(Block.jarGlass, BlockSounds.GLASS);

        addDispatch(Block.overlayPebbles, BlockSounds.STONE);

        addDispatch(Block.fenceChainlink, BlockSounds.METAL);
        addDispatch(Block.fencePaperWall, BlockSounds.CLOTH);
        addDispatch(Block.paperWall, BlockSounds.CLOTH);

        validate();
    }

    @Override
    protected BlockSound getDefault()
    {
        return BlockSounds.DEFAULT;
    }

    private void validate()
    {
        for (Block block : Block.blocksList)
        {
            if (block != null && dispatches.get(block) == null)
            {
                throw new RuntimeException("Block " + block.getKey() + " has no assigned sound!");
            }
        }
    }
}
\ No newline at end of file
diff --git a/src/main/java/net/minecraft/core/util/helper/ScreenShot.java b/src/main/java/net/minecraft/core/util/helper/ScreenShot.java
index 5dc4f4227..843f079b3 100644
--- a/src/main/java/net/minecraft/core/util/helper/ScreenShot.java
+++ b/src/main/java/net/minecraft/core/util/helper/ScreenShot.java
@@ -55,7 +55,7 @@ public class ScreenShot
 
             }
 
-            BufferedImage bufferedimage = new BufferedImage(width, height, 1);
+            BufferedImage bufferedimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
             bufferedimage.setRGB(0, 0, width, height, imageData, 0, width);
             ImageIO.write(bufferedimage, "png", file2);
             try {
diff --git a/src/main/java/net/minecraft/core/world/World.java b/src/main/java/net/minecraft/core/world/World.java
index caebad2d4..39c84d7c1 100644
--- a/src/main/java/net/minecraft/core/world/World.java
+++ b/src/main/java/net/minecraft/core/world/World.java
@@ -14,7 +14,9 @@ import java.util.TreeSet;
 
 import com.mojang.nbt.CompoundTag;
 
+import net.minecraft.client.render.LightmapHelper;
 import net.minecraft.client.render.camera.ICamera;
+import net.minecraft.client.world.chunk.provider.ChunkProviderViewer;
 import net.minecraft.core.Global;
 import net.minecraft.core.HitResult;
 import net.minecraft.core.NextTickListEntry;
@@ -61,6 +63,8 @@ import net.minecraft.core.world.saveddata.SavedDataStorage;
 import net.minecraft.core.world.season.SeasonManager;
 import net.minecraft.core.world.season.Seasons;
 import net.minecraft.core.world.type.WorldType;
+import net.minecraft.core.world.type.WorldTypeDebug;
+import net.minecraft.core.world.type.WorldTypes;
 import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.weather.WeatherManager;
 
@@ -270,6 +274,22 @@ public class World implements WorldSource {
 
         biomeProvider = this.worldType.createBiomeProvider(this);
     }
+    // Used for the model viewer
+    public World(){
+        this.dimension = Dimension.overworld;
+        this.saveHandler = null;
+        levelData = new LevelData(0, "modelviewer");
+        this.worldType = WorldTypes.DEBUG;
+        chunkProvider = new ChunkProviderViewer(this);
+        seasonManager = SeasonManager.fromConfig(this, this.worldType.getDefaultSeasonConfig());
+        updateSkyBrightness();
+
+        this.weatherManager = new WeatherManager(this);
+
+        auroraProvider = new AuroraProvider(this, 0);
+
+        biomeProvider = this.worldType.createBiomeProvider(this);
+    }
 
     public <T> T getGameRule(GameRule<T> gameRule)
     {
@@ -1061,15 +1081,21 @@ public class World implements WorldSource {
         }
     }
 
+	@Override
+	public float getBrightness(int x, int y, int z, int blockLightValue) {
+		int i1 = getBlockLightValue(x, y, z);
+		if(i1 < blockLightValue) {
+			i1 = blockLightValue;
+		}
+		return worldType.getBrightnessRamp()[i1];
+	}
+    
     @Override
-    public float getBrightness(int x, int y, int z, int blockLightValue)
-    {
-        int i1 = getBlockLightValue(x, y, z);
-        if(i1 < blockLightValue)
-        {
-            i1 = blockLightValue;
-        }
-        return worldType.getBrightnessRamp()[i1];
+    public int getLightmapCoord(int x, int y, int z, int blockLightValue) {
+		int skyLight = getSavedLightValue(LightLayer.Sky, x, y, z);
+		int blockLight = Math.max(getSavedLightValue(LightLayer.Block, x, y, z), blockLightValue);
+		
+		return LightmapHelper.getLightmapCoord(skyLight, blockLight);
     }
 
     @Override
@@ -1112,7 +1138,7 @@ public class World implements WorldSource {
         int id = getBlockId(blockStartX, blockStartY, blockStartZ);
         int meta = getBlockMetadata(blockStartX, blockStartY, blockStartZ);
         Block block = Block.blocksList[id];
-        if((!flag1 || block == null || block.getCollisionBoundingBoxFromPool(this, blockStartX, blockStartY, blockStartZ) != null) && id > 0 && block.canCollideCheck(meta, shouldCollideWithFluids))
+        if((!flag1 || block == null || block.getCollisionBoundingBoxFromPool(this, blockStartX, blockStartY, blockStartZ) != null) && id > 0 && (block.canCollideCheck(meta, shouldCollideWithFluids)))
         {
             HitResult movingobjectposition = block.collisionRayTrace(this, blockStartX, blockStartY, blockStartZ, start, end);
             if(movingobjectposition != null)
@@ -1518,6 +1544,28 @@ public class World implements WorldSource {
 
         return collidingBoundingBoxes;
     }
+	
+	public float getAmbientBrightness(float partialTicks) {
+		float angle = getCelestialAngle(partialTicks);
+		float bright = 1.0F - (MathHelper.cos(angle * 3.141593F * 2.0F) * 2.0F + 0.2F);
+		bright = 1.0f - MathHelper.clamp(bright, 0.0f, 1.0f);
+		
+		Weather weather = weatherManager.getCurrentWeather();
+		if(weather != null) {
+			// TODO Unhardcode somehow
+			if(weather == Weather.overworldRain) {
+				float power = weatherManager.getWeatherIntensity() * weatherManager.getWeatherPower();
+				bright = (float) (bright * (1.0 - (power * 5.0f) / 16.0));	
+			}
+			if(weather == Weather.overworldStorm) {
+				float power = weatherManager.getWeatherIntensity() * weatherManager.getWeatherPower();
+				bright = (float) (bright * (1.0 - (power * 5.0f) / 16.0));
+				bright = (float) (bright * (1.0 - (power * 5.0f) / 16.0));
+			}
+		}
+		
+		return bright * 0.8f + 0.2f;
+	}
 
     public Vec3d getSkyColor(ICamera camera, float partialTick)
     {
diff --git a/src/main/java/net/minecraft/core/world/WorldSource.java b/src/main/java/net/minecraft/core/world/WorldSource.java
index de1b74b9b..10699959d 100644
--- a/src/main/java/net/minecraft/core/world/WorldSource.java
+++ b/src/main/java/net/minecraft/core/world/WorldSource.java
@@ -4,8 +4,6 @@ import net.minecraft.core.block.Block;
 import net.minecraft.core.block.entity.TileEntity;
 import net.minecraft.core.block.material.Material;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.biome.provider.BiomeProvider;
-import net.minecraft.core.world.season.Season;
 import net.minecraft.core.world.season.SeasonManager;
 
 public interface WorldSource
@@ -18,6 +16,8 @@ public interface WorldSource
     TileEntity getBlockTileEntity(int x, int y, int z);
 
     float getBrightness(int x, int y, int z, int blockLightValue);
+    
+    int getLightmapCoord(int x, int y, int z, int blockLightValue);
 
     float getLightBrightness(int x, int y, int z);
 
diff --git a/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java b/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
index 805af9a82..712560b4a 100644
--- a/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
+++ b/src/main/java/net/minecraft/core/world/chunk/ChunkCache.java
@@ -1,16 +1,17 @@
 package net.minecraft.core.world.chunk;
 
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.block.material.Material;
+import net.minecraft.core.enums.LightLayer;
+import net.minecraft.core.world.World;
+
 // Referenced classes of package net.minecraft.src:
 //            IBlockAccess, World, Chunk, WorldProvider, 
 //            Block, Material, TileEntity, WorldChunkManager
 
 import net.minecraft.core.world.WorldSource;
-import net.minecraft.core.world.World;
-import net.minecraft.core.block.entity.TileEntity;
-import net.minecraft.core.block.Block;
-import net.minecraft.core.block.material.Material;
 import net.minecraft.core.world.biome.Biome;
-import net.minecraft.core.world.biome.provider.BiomeProvider;
 import net.minecraft.core.world.season.SeasonManager;
 
 public class ChunkCache
@@ -99,16 +100,22 @@ public class ChunkCache
         }
     }
 
-    @Override
-	public float getBrightness(int x, int y, int z, int blockLightValue)
-    {
-        int i1 = getLightValue(x, y, z);
-        if(i1 < blockLightValue)
-        {
-            i1 = blockLightValue;
-        }
-        return worldObj.worldType.getBrightnessRamp()[i1];
-    }
+	@Override
+	public float getBrightness(int x, int y, int z, int blockLightValue) {
+		int i1 = getLightValue(x, y, z);
+		if(i1 < blockLightValue) {
+			i1 = blockLightValue;
+		}
+		return worldObj.worldType.getBrightnessRamp()[i1];
+	}
+
+	@Override
+	public int getLightmapCoord(int x, int y, int z, int blockLightValue) {
+		int skyLight = worldObj.getSavedLightValue(LightLayer.Sky, x, y, z);
+		int blockLight = Math.max(worldObj.getSavedLightValue(LightLayer.Block, x, y, z), blockLightValue);
+		
+		return skyLight << 20 | blockLight << 4;
+	}
 
     @Override
 	public float getLightBrightness(int x, int y, int z)
diff --git a/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java b/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java
new file mode 100644
index 000000000..ec705341c
--- /dev/null
+++ b/src/main/java/net/minecraft/core/world/chunk/DisplayChunk.java
@@ -0,0 +1,74 @@
+package net.minecraft.core.world.chunk;
+
+import net.minecraft.core.block.entity.TileEntity;
+import net.minecraft.core.enums.LightLayer;
+import net.minecraft.core.world.World;
+
+public class DisplayChunk extends EmptyChunk{
+    public static int displayBlockId = 0;
+    public static int displayBlockMeta = 0;
+    public static int displayBlockPosX = 0;
+    public static int displayBlockPosY = 0;
+    public static int displayBlockPosZ = 0;
+    public static TileEntity displayTileEntity = null;
+    public DisplayChunk(World world, int x, int z) {
+        super(world, x, z);
+    }
+    @Override
+    public int getBlockID(int x, int y, int z)
+    {
+        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+            return displayBlockId;
+        }
+        return 0;
+    }
+    @Override
+    public int getBlockMetadata(int x, int y, int z)
+    {
+        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+            return displayBlockMeta;
+        }
+        return 0;
+    }
+    @Override
+    public int getBrightness(LightLayer layer, int x, int y, int z)
+    {
+        return 15;
+    }
+    @Override
+    public void setTileEntity(int x, int y, int z, TileEntity tileEntity)
+    {
+        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+            displayTileEntity = tileEntity;
+            displayTileEntity.worldObj = world;
+            displayTileEntity.x = x;
+            displayTileEntity.y = y;
+            displayTileEntity.z = z;
+        }
+    }
+
+    @Override
+    public void removeTileEntity(int x, int y, int z)
+    {
+        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+            displayTileEntity = null;
+        }
+    }
+    @Override
+    public TileEntity getTileEntity(int x, int y, int z)
+    {
+        if (x == displayBlockPosX && y == displayBlockPosY && z == displayBlockPosZ){
+            return displayTileEntity;
+        }
+        return null;
+    }
+    public static void setDisplayTileEntity(World world, TileEntity entity){
+        displayTileEntity = entity;
+        if (displayTileEntity != null){
+            displayTileEntity.worldObj = world;
+            displayTileEntity.x = DisplayChunk.displayBlockPosX;
+            displayTileEntity.y = DisplayChunk.displayBlockPosY;
+            displayTileEntity.z = DisplayChunk.displayBlockPosZ;
+        }
+    }
+}
diff --git a/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java b/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
index 806b1a267..5bfae16bc 100644
--- a/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
+++ b/src/main/java/net/minecraft/core/world/generate/chunk/perlin/overworld/ChunkDecoratorOverworld.java
@@ -294,12 +294,12 @@ public class ChunkDecoratorOverworld
             byteOrchid = 1;
         }
         for (int l14 = 0; l14 < byteOrchid; l14++) {
-            int blockId = Block.flowerPink.id;
+            int[] flowerIds= { Block.flowerYellow.id, Block.flowerPink.id, Block.flowerRed.id };
 
             int l19 = x + rand.nextInt(16) + 8;
             int k22 = rand.nextInt(world.getHeightBlocks());
             int j24 = z + rand.nextInt(16) + 8;
-            (new WorldFeatureTallGrass(blockId)).generate(world, rand, l19, k22, j24);
+            (new WorldFeatureMeadow(flowerIds)).generate(world, rand, l19, k22, j24);
         }
 
         byte byteMeadow = 0;
diff --git a/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMeadow.java b/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMeadow.java
new file mode 100644
index 000000000..7117c3419
--- /dev/null
+++ b/src/main/java/net/minecraft/core/world/generate/feature/WorldFeatureMeadow.java
@@ -0,0 +1,45 @@
+package net.minecraft.core.world.generate.feature;
+
+import net.minecraft.core.block.Block;
+import net.minecraft.core.block.BlockLeavesBase;
+import net.minecraft.core.world.World;
+import org.lwjgl.Sys;
+
+import java.util.List;
+import java.util.Random;
+
+public class WorldFeatureMeadow extends WorldFeature
+{
+
+    public WorldFeatureMeadow(int[] blockIds)
+    {
+        this.blockIds = blockIds;
+    }
+
+    @Override
+    public boolean generate(World world, Random random, int x, int y, int z)
+    {
+        for(int l = 0; ((l = world.getBlockId(x, y, z)) == 0 || Block.blocksList[l] instanceof BlockLeavesBase) && y > 0; y--) { }
+        for(int i1 = 0; i1 < 128; i1++)
+        {
+            int j1 = (x + random.nextInt(8)) - random.nextInt(8);
+            int k1 = (y + random.nextInt(4)) - random.nextInt(4);
+            int l1 = (z + random.nextInt(8)) - random.nextInt(8);
+
+            int meta = 0;
+
+            int index = random.nextInt(blockIds.length);
+            int flowerId = blockIds[index];
+
+
+            if(world.isAirBlock(j1, k1, l1) && Block.blocksList[flowerId].canBlockStay(world, j1, k1, l1))
+            {
+                world.setBlockAndMetadata(j1, k1, l1, flowerId, meta);
+            }
+        }
+
+        return true;
+    }
+
+    private final int[] blockIds;
+}
diff --git a/src/main/java/net/minecraft/core/world/type/WorldType.java b/src/main/java/net/minecraft/core/world/type/WorldType.java
index 54c62c39f..f7c43bfea 100644
--- a/src/main/java/net/minecraft/core/world/type/WorldType.java
+++ b/src/main/java/net/minecraft/core/world/type/WorldType.java
@@ -1,13 +1,11 @@
 package net.minecraft.core.world.type;
 
-import net.minecraft.core.Global;
 import net.minecraft.core.util.phys.Vec3d;
 import net.minecraft.core.world.World;
 import net.minecraft.core.world.biome.provider.BiomeProvider;
 import net.minecraft.core.world.config.season.SeasonConfig;
 import net.minecraft.core.world.generate.chunk.ChunkGenerator;
 import net.minecraft.core.world.save.LevelData;
-import net.minecraft.core.world.season.Season;
 import net.minecraft.core.world.weather.Weather;
 import net.minecraft.core.world.wind.WindManager;
 
diff --git a/src/main/resources/assets/minecraft/textures/block/flower_light_blue.png b/src/main/resources/assets/minecraft/textures/block/flower_light_blue.png
index f8bbe910c..d814a7c67 100644
Binary files a/src/main/resources/assets/minecraft/textures/block/flower_light_blue.png and b/src/main/resources/assets/minecraft/textures/block/flower_light_blue.png differ
diff --git a/src/main/resources/assets/minecraft/textures/block/flower_pink.png b/src/main/resources/assets/minecraft/textures/block/flower_pink.png
index 32c543c79..0a121d122 100644
Binary files a/src/main/resources/assets/minecraft/textures/block/flower_pink.png and b/src/main/resources/assets/minecraft/textures/block/flower_pink.png differ
diff --git a/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_bottom.png b/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_bottom.png
new file mode 100644
index 000000000..358667db6
Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_bottom.png differ
diff --git a/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_inside.png b/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_inside.png
new file mode 100644
index 000000000..5b4db2c4f
Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_inside.png differ
diff --git a/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_side.png b/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_side.png
new file mode 100644
index 000000000..ed9cd1d7e
Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_side.png differ
diff --git a/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_top.png b/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_top.png
new file mode 100644
index 000000000..6a04b62ba
Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/block/pumpkin_pie_top.png differ
diff --git a/src/main/resources/assets/minecraft/textures/item/food_pumpkin_pie.png b/src/main/resources/assets/minecraft/textures/item/food_pumpkin_pie.png
new file mode 100644
index 000000000..368a857e6
Binary files /dev/null and b/src/main/resources/assets/minecraft/textures/item/food_pumpkin_pie.png differ
