diff --git a/src/main/java/net/minecraft/client/player/controller/PlayerController.java b/src/main/java/net/minecraft/client/player/controller/PlayerController.java
index 13334491a..c489d994d 100644
--- a/src/main/java/net/minecraft/client/player/controller/PlayerController.java
+++ b/src/main/java/net/minecraft/client/player/controller/PlayerController.java
@@ -34,6 +34,7 @@ public abstract class PlayerController {
 	//Called when the mouse is clicked and about 5 times per second while the button is held down
 	//Repeat is false when the mouse was clicked this frame
 	public void startDestroyBlock(int x, int y, int z, Side side, double xHit, double yHit, boolean repeat) {
+		if (!mc.thePlayer.getGamemode().canInteract()) return;
 		if(!mc.thePlayer.getGamemode().doBlockBreakingAnim()) {
 			swingItem(true);
 			
@@ -62,7 +63,7 @@ public abstract class PlayerController {
 	
 	//Called 20 times per second when the mouse button is held and blocks are targeted
 	public void continueDestroyBlock(int x, int y, int z, Side side, double xHit, double yHit) {
-		if(!mc.thePlayer.getGamemode().doBlockBreakingAnim()) {
+		if(!mc.thePlayer.getGamemode().doBlockBreakingAnim() || !mc.thePlayer.getGamemode().canInteract()) {
 			return;
 		}
 		
@@ -143,6 +144,7 @@ public abstract class PlayerController {
 	}
 
 	public boolean destroyBlock(int x, int y, int z, Side side, EntityPlayer player) {
+		if (!player.getGamemode().canInteract()) return false;
 		setMineBlock(null, null, null);
 		World world = mc.theWorld;
 		Block block = Block.getBlock(world.getBlockId(x, y, z));
@@ -177,6 +179,7 @@ public abstract class PlayerController {
 	}
 	
 	protected void hitBlock(int x, int y, int z, Side side, double xHit, double yHit) {
+		if (!mc.thePlayer.getGamemode().canInteract()) return;
 		mc.theWorld.onBlockHit(mc.thePlayer, x, y, z, side);
 		
 		Block block = Block.getBlock(mc.theWorld.getBlockId(x, y, z));
@@ -268,10 +271,12 @@ public abstract class PlayerController {
 	}
 
 	public boolean interact(EntityPlayer entityplayer, Entity entity) {
+		if (!entityplayer.getGamemode().canInteract()) return false;
 		return entityplayer.useCurrentItemOnEntity(entity);
 	}
 
 	public void attack(EntityPlayer entityplayer, Entity entity) {
+		if (!entityplayer.getGamemode().canInteract()) return;
 		entityplayer.attackTargetEntityWithCurrentItem(entity);
 	}
 
diff --git a/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java b/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java
index 64de6e9c6..1861f75e1 100644
--- a/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java
+++ b/src/main/java/net/minecraft/client/player/controller/PlayerControllerSP.java
@@ -15,6 +15,7 @@ public class PlayerControllerSP extends PlayerController {
 
 	@Override
 	public boolean destroyBlock(int x, int y, int z, Side side, EntityPlayer player) {
+		if (!player.getGamemode().canInteract()) return false;
 		int id = mc.theWorld.getBlockId(x, y, z);
 		int meta = mc.theWorld.getBlockMetadata(x, y, z);
 		TileEntity tileEntity = mc.theWorld.getBlockTileEntity(x, y, z);
diff --git a/src/main/java/net/minecraft/core/player/gamemode/Gamemode.java b/src/main/java/net/minecraft/core/player/gamemode/Gamemode.java
index 184763b8c..5de567958 100644
--- a/src/main/java/net/minecraft/core/player/gamemode/Gamemode.java
+++ b/src/main/java/net/minecraft/core/player/gamemode/Gamemode.java
@@ -199,5 +199,5 @@ public abstract class Gamemode
 	public static final Gamemode creative = new GamemodeCreative(1, "gamemode.creative").setIsPlayerInvulnerable().setCanPlayerFly().setIsImmuneToFire().setInstantPortalTravel().setBlockReachDistance(6.0f).setEntityReachDistance(4.5f);
 	public static final Gamemode hardcore = new GamemodeSurvival(2, "gamemode.hardcore").setConsumeBlocks().setDoBlockBreakingAnim().setToolDurability().setDropBlockOnBreak().setAreMobsHostile().setPermaDeath();
 	public static final Gamemode adventure = new GamemodeSurvival(3, "gamemode.adventure").setConsumeBlocks().setDoBlockBreakingAnim().setToolDurability().setDropBlockOnBreak().setAreMobsHostile().setRequireToolToBreak();
-	public static final Gamemode spectator = new GamemodeSurvival(4, "gamemode.spectator").setIsPlayerInvulnerable().setCanPlayerFly().setIsImmuneToFire().setInstantPortalTravel().setBlockReachDistance(0).setEntityReachDistance(0).setCantInteract().setHideFromWorldCreation();
+	public static final Gamemode spectator = new GamemodeSurvival(4, "gamemode.spectator").setIsPlayerInvulnerable().setCanPlayerFly().setIsImmuneToFire().setInstantPortalTravel().setBlockReachDistance(5000).setEntityReachDistance(5000).setCantInteract().setHideFromWorldCreation();
 }
diff --git a/src/main/java/net/minecraft/core/world/SpawnerMobs.java b/src/main/java/net/minecraft/core/world/SpawnerMobs.java
index 6ea3c8e13..9f7098a11 100644
--- a/src/main/java/net/minecraft/core/world/SpawnerMobs.java
+++ b/src/main/java/net/minecraft/core/world/SpawnerMobs.java
@@ -32,11 +32,11 @@ public final class SpawnerMobs
     {
     }
 
-    private static ChunkPosition getRandomSpawningPointInChunk(World world, int x, int z)
+    private static ChunkPosition getRandomSpawningPointInChunk(World world, int chunkX, int chunkZ)
     {
-        int newX = x + world.rand.nextInt(16);
+        int newX = (chunkX * 16) + world.rand.nextInt(16);
         int newY = world.rand.nextInt(world.getHeightBlocks());
-        int newZ = z + world.rand.nextInt(16);
+        int newZ = (chunkZ * 16) + world.rand.nextInt(16);
         return new ChunkPosition(newX, newY, newZ);
     }
 
@@ -46,8 +46,8 @@ public final class SpawnerMobs
         eligibleChunksForSpawning.clear();
 
         for (EntityPlayer player : world.players){
-            final int playerChunkX = MathHelper.floor_double(player.x / Chunk.CHUNK_SIZE_X);
-            final int playerChunkZ = MathHelper.floor_double(player.z / Chunk.CHUNK_SIZE_Z);
+            final int playerChunkX = MathHelper.floor_double(player.x / (double) Chunk.CHUNK_SIZE_X);
+            final int playerChunkZ = MathHelper.floor_double(player.z / (double) Chunk.CHUNK_SIZE_Z);
             final byte spawnRadius = 8;
 
             for(int dx = -spawnRadius; dx <= spawnRadius; ++dx) {
@@ -60,11 +60,11 @@ public final class SpawnerMobs
         }
 
         int totalSpawned = 0;
-        final ChunkCoordinates spawnChunk = world.getSpawnPoint();
+        final ChunkCoordinates spawnPoint = world.getSpawnPoint();
         final ChunkCoordinate[] spawnChunks = new ChunkCoordinate[3 * 3];
         for (int x = 0; x < 3; x++) {
             for (int z = 0; z < 3; z++) {
-                spawnChunks[x * 3 + z] = new ChunkCoordinate(spawnChunk.x + (x - 1), spawnChunk.z + (z - 1));
+                spawnChunks[x * 3 + z] = new ChunkCoordinate((spawnPoint.x & 0xF) + (x - 1), (spawnPoint.z & 0xF) + (z - 1));
             }
         }
 
@@ -76,7 +76,7 @@ public final class SpawnerMobs
             if (world.countEntities(creatureType.getCreatureClass()) > ((creatureType.getMaxNumberOfCreature() * eligibleChunksForSpawning.size()) / 256))
                 continue;
 
-            for (ChunkCoordinate chunk : eligibleChunksForSpawning) {
+            chunkLoop: for (ChunkCoordinate chunk : eligibleChunksForSpawning) {
                 boolean checkSpawnDist = false;
                 for (ChunkCoordinate c : spawnChunks){
                     if (c.equals(chunk)){
@@ -111,11 +111,11 @@ public final class SpawnerMobs
                     }
                 }
 
-                final ChunkPosition pos = getRandomSpawningPointInChunk(world, blockX, blockZ);
+                final ChunkPosition pos = getRandomSpawningPointInChunk(world, chunk.x, chunk.z);
                 final int x = pos.x;
                 final int y = pos.y;
                 final int z = pos.z;
-                if (/*world.isBlockNormalCube(x, y, z) || */world.getBlockMaterial(x, y, z) != creatureType.getCreatureMaterial())
+                if (world.isBlockNormalCube(x, y, z) || world.getBlockMaterial(x, y, z) != creatureType.getCreatureMaterial())
                     continue;
 
                 int countSpawned = 0;
@@ -139,9 +139,9 @@ public final class SpawnerMobs
 
                         // Forbid mob spawning in a 24 block radius around spawn
                         if (checkSpawnDist) {
-                            final double spawnDistanceX = dx - spawnChunk.x;
-                            final double spawnDistanceY = dy - spawnChunk.y;
-                            final double spawnDistanceZ = dz - spawnChunk.z;
+                            final double spawnDistanceX = dx - spawnPoint.x;
+                            final double spawnDistanceY = dy - spawnPoint.y;
+                            final double spawnDistanceZ = dz - spawnPoint.z;
                             final double spawnDistanceSquared = spawnDistanceX * spawnDistanceX + spawnDistanceY * spawnDistanceY + spawnDistanceZ * spawnDistanceZ;
                             if (spawnDistanceSquared < 576.0F) continue;
                         }
@@ -163,7 +163,7 @@ public final class SpawnerMobs
                         mobToSpawn.spawnInit();
                         world.entityJoinedWorld(mobToSpawn);
                         if (countSpawned >= mobToSpawn.getMaxSpawnedInChunk()) {
-                            break;
+                            continue chunkLoop;
                         }
                     }
                 }
diff --git a/src/main/java/net/minecraft/server/net/handler/NetServerHandler.java b/src/main/java/net/minecraft/server/net/handler/NetServerHandler.java
index 2f341f0d7..939c9e49e 100644
--- a/src/main/java/net/minecraft/server/net/handler/NetServerHandler.java
+++ b/src/main/java/net/minecraft/server/net/handler/NetServerHandler.java
@@ -357,6 +357,7 @@ public class NetServerHandler extends NetHandler
         final int y = packet.yPosition;
         final int z = packet.zPosition;
 
+        if (!playerEntity.getGamemode().canInteract()) return;
         WorldServer world = mcServer.getDimensionWorld(playerEntity.dimension);
         if(packet.status == 4) {
             // Drop single item
@@ -420,6 +421,7 @@ public class NetServerHandler extends NetHandler
     @Override
     public void handlePlace(Packet15Place packet)
     {
+        if (!playerEntity.getGamemode().canInteract()) return;
         WorldServer worldserver = mcServer.getDimensionWorld(playerEntity.dimension);
         ItemStack itemstack = playerEntity.inventory.getCurrentItem();
         boolean flag = worldserver.field_819_z = worldserver.dimension.id != 0 || mcServer.playerList.isOp(playerEntity.username);
@@ -690,6 +692,7 @@ public class NetServerHandler extends NetHandler
     @Override
     public void handleUseEntity(Packet7UseEntity packet)
     {
+        if (!playerEntity.getGamemode().canInteract()) return;
         WorldServer worldserver = mcServer.getDimensionWorld(playerEntity.dimension);
         Entity targetEntity = worldserver.getEntityFromId(packet.targetEntity);
         if (targetEntity != null && playerEntity.distanceToSqr(targetEntity) < 36D)
@@ -795,6 +798,7 @@ public class NetServerHandler extends NetHandler
     @Override
     public void handleUpdateSign(Packet130UpdateSign packet)
     {
+        if (!playerEntity.getGamemode().canInteract()) return;
         WorldServer worldserver = mcServer.getDimensionWorld(playerEntity.dimension);
         if (worldserver.isBlockLoaded(packet.xPosition, packet.yPosition, packet.zPosition))
         {
