gt: 				int rz = z - cz * 16;
context: /**
   * AnvilCleaner - a free Minecraft map decorruption tool
   * Copyright (C) dmulloy2 <http://dmulloy2.net>
   * Copyright (C) Contributors
   *
   * This program is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  package net.dmulloy2.anvilcleaner.util;
  
  import java.util.List;
  import java.util.Map;
  
  import net.dmulloy2.anvilcleaner.AnvilCleaner;
  import net.dmulloy2.anvilcleaner.types.EntityType;
  import net.dmulloy2.anvilcleaner.types.Options;
  import net.dmulloy2.anvilcleaner.types.TileEntityType;
  
  import com.mojang.nbt.CompoundTag;
  import com.mojang.nbt.DoubleTag;
  import com.mojang.nbt.ListTag;
  import com.mojang.nbt.Tag;
  
  public class ChunkStorage
  {
  	public static class LevelChunk
  	{
  		public byte version;                      /* V */
  		public int x;                             /* xPos */
  		public int z;                             /* zPos */
  		public long lastUpdate;                   /* LastUpdate */
  		public int[] heightMap;                   /* HeightMap */
  		public boolean terrainPopulated;          /* TerrainPopulated */
  		public boolean lightPopulated;            /* LightPopulated */
  		public long inhabitedTime;                /* InhabitedTime */
  		public ListTag<CompoundTag> sections;     /* Sections */
  		public byte[] biomes;                     /* Biomes */
  		public ListTag<CompoundTag> entities;     /* Entities */
  		public ListTag<CompoundTag> tileEntities; /* TileEntities */
  		public ListTag<CompoundTag> tileTicks;    /* TileTicks */
  
  		public Map<String, Tag> extraTags;
  
  		public LevelChunk(int x, int z)
  		{
  			this.x = x;
  			this.z = z;
  		}
  	}
  
  	public static LevelChunk load(CompoundTag tag)
  	{
  		Map<String, Tag> extraTags = tag.getAllTags();
  
  		int x = tag.getInt("xPos");
  		extraTags.remove("xPos");
  
  		int z = tag.getInt("zPos");
  		extraTags.remove("zPos");
  
  		LevelChunk chunk = new LevelChunk(x, z);
  
  		chunk.version = tag.getByte("V");
  		extraTags.remove("V");
  
  		chunk.lastUpdate = tag.getLong("LastUpdate");
  		extraTags.remove("LastUpdate");
  
  		chunk.heightMap = tag.getIntArray("HeightMap");
  		extraTags.remove("HeightMap");
  
  		chunk.terrainPopulated = tag.getBoolean("TerrainPopulated");
  		extraTags.remove("TerrainPopulated");
  
  		chunk.lightPopulated = tag.getBoolean("LightPopulated");
  		extraTags.remove("LightPopulated");
  
  		chunk.inhabitedTime = tag.getLong("InhabitedTime");
  		extraTags.remove("InhabitedTime");
  
  		chunk.sections = tag.getList("Sections");
  		extraTags.remove("Sections");
  
  		chunk.biomes = tag.getByteArray("Biomes");
  		extraTags.remove("Biomes");
  
  		chunk.entities = tag.getList("Entities");
  		extraTags.remove("Entities");
  
  		chunk.tileEntities = tag.getList("TileEntities");
  		extraTags.remove("TileEntities");
  
  		chunk.tileTicks = tag.getList("TileTicks");
  		extraTags.remove("TileTicks");
  
  		chunk.extraTags = extraTags;
  		return chunk;
  	}
  
  	public static CompoundTag getSection(int section, ListTag<CompoundTag> sections)
  	{
  		for (int i = 0; i < sections.size(); i++)
  		{
  			CompoundTag sectionTag = sections.get(i);
  			if (sectionTag != null && sectionTag.getByte("Y") == section)
  				return sectionTag;
  		}
  
  		return null;
  	}
  
  	public static boolean sectionExists(int section, ListTag<CompoundTag> sections)
  	{
  		for (int i = 0; i < sections.size(); i++)
  		{
  			CompoundTag sectionTag = sections.get(i);
  			if (sectionTag != null && sectionTag.getByte("Y") == section)
  				return true;
  		}
  
  		return false;
  	}
  
  	public static int clean(AnvilCleaner anvilCleaner, LevelChunk data, CompoundTag tag, int cx, int cz, Options options)
  	{
  		int fixes = 0;
  
  		anvilCleaner.log("Cleaning chunk at {0}, {1}...", cx, cz);
  
  		tag.putByte("V", data.version);
  
  		if (options.chunkPositions && (cx != data.x || cz != data.z))
  		{
  			anvilCleaner.log("Chunk at {0}, {1} had the wrong position. Correcting...", cx, cz);
  			fixes++;
  
  			tag.putInt("xPos", cx);
  			tag.putInt("zPos", cz);
  		}
  		else
  		{
  			tag.putInt("xPos", data.x);
  			tag.putInt("zPos", data.z);
  		}
  
  		tag.putLong("LastUpdate", data.lastUpdate);
  
  		int[] newHeight = new int[256];
  		for (int i = 0; i < data.heightMap.length; i++)
  		{
  			newHeight[i] = data.heightMap[i];
  		}
  
  		tag.putIntArray("HeightMap", newHeight);
  
  		if (options.fixTerrainPopulation)
  		{
  			if (! data.terrainPopulated)
  			{
  				anvilCleaner.log("Terrain populated was false... Setting to true!");
  				fixes++;
  			}
  
  			tag.putBoolean("TerrainPopulated", true);
  		}
  		else
  		{
  			tag.putBoolean("TerrainPopulated", data.terrainPopulated);
  		}
  
  		tag.putBoolean("LightPopulated", data.lightPopulated);
  		tag.putLong("InhabitedTime", data.inhabitedTime);
  
  		if (options.blockCorruption)
  		{
  			ListTag<CompoundTag> sectionTags = new ListTag<CompoundTag>("Sections");
  			for (int i = 0; i < data.sections.size(); i++)
  			{
  				CompoundTag sectionTag = data.sections.get(i);
  				CompoundTag newSectionTag = new CompoundTag();
  
  				byte[] blocks = sectionTag.getByteArray("Blocks");
  
  				if (blocks.length == 4096)
  				{
  					newSectionTag.putByte("Y", sectionTag.getByte("Y"));
  
  					newSectionTag.putByteArray("Blocks", blocks);
  
  					if (sectionTag.getByteArray("Data").length != 2048)
  					{
  						anvilCleaner.log("Corrupted data detected in section {2} of chunk at ({0}, {1}). Fixing...", data.x, data.z,
  								sectionTag.getByte("Y"));
  						fixes++;
  
  						if (options.deleteCorrupt)
  						{
  							return -1;
  						}
  
  						newSectionTag.putByteArray("Data", new byte[2048]);
  					}
  					else
  					{
  						byte[] newData = new byte[2048];
  						byte[] oldData = sectionTag.getByteArray("Data");
  
  						for (int j = 0; j < 2048; j++)
  						{
  							newData[j] = oldData[j];
  						}
  
  						newSectionTag.putByteArray("Data", newData);
  					}
  
  					if (options.lightingCorruption)
  					{
  						if (sectionTag.getByteArray("BlockLight").length != 2048)
  						{
  							anvilCleaner.log("Corrupted block lighting detected in section {2} of chunk at ({0}, {1}). Fixing...",
  									Integer.valueOf(data.x), Integer.valueOf(data.z), Byte.valueOf(sectionTag.getByte("Y")));
  							fixes++;
  
  							if (options.deleteCorrupt)
  							{
  								return -1;
  							}
  
  							newSectionTag.putByteArray("BlockLight", new byte[2048]);
  						}
  						else
  						{
  							byte[] newData = new byte[2048];
  							byte[] oldData = sectionTag.getByteArray("BlockLight");
  
  							for (int j = 0; j < 2048; j++)
  							{
  								newData[j] = oldData[j];
  							}
  
  							newSectionTag.putByteArray("BlockLight", newData);
  						}
  
  						if (sectionTag.getByteArray("SkyLight").length != 2048)
  						{
  							anvilCleaner.log("Corrupted sky lighting detected in section {2} of chunk at ({0}, {1}). Fixing...",
  									Integer.valueOf(data.x), Integer.valueOf(data.z), Byte.valueOf(sectionTag.getByte("Y")));
  							fixes++;
  
  							if (options.deleteCorrupt)
  							{
  								return -1;
  							}
  
  							newSectionTag.putByteArray("SkyLight", new byte[2048]);
  						}
  						else
  						{
  							byte[] newData = new byte[2048];
  							byte[] oldData = sectionTag.getByteArray("SkyLight");
  
  							for (int j = 0; j < 2048; j++)
  							{
  								newData[j] = oldData[j];
  							}
  
  							newSectionTag.putByteArray("SkyLight", newData);
  						}
  					}
  					else
  					{
  						newSectionTag.putByteArray("BlockLight", sectionTag.getByteArray("BlockLight"));
  						newSectionTag.putByteArray("SkyLight", sectionTag.getByteArray("SkyLight"));
  					}
  
  					if (sectionTag.getByteArray("Add").length != 0)
  					{
  						newSectionTag.putByteArray("Add", sectionTag.getByteArray("Add"));
  					}
  
  					sectionTags.add(sectionTag);
  				}
  				else
  				{
  					return -1;
  				}
  			}
  
  			tag.put("Sections", sectionTags);
  		}
  		else
  		{
  			tag.put("Sections", data.sections);
  		}
  
  		if (data.biomes.length == 256)
  		{
  			tag.putByteArray("Biomes", data.biomes);
  		}
  
  		if (options.entities)
  		{
  			ListTag<CompoundTag> entityTags = new ListTag<CompoundTag>("Entities");
  			if (options.savePersistentEntities)
  			{
  				for (int i = 0; i < data.entities.size(); i++)
  				{
  					CompoundTag entity = data.entities.get(i);
  					ListTag<DoubleTag> pos = entity.getList("Pos");
  					double x = pos.get(0).data;
  					double y = pos.get(1).data;
  					double z = pos.get(2).data;
  
  					String id = entity.getString("id");
  					EntityType type = EntityType.getById(id);
  					if (type != null)
  					{
  						if (type.isPersistent())
  						{
  							entityTags.add(entity);
  						}
  						else
  						{
  							anvilCleaner.log("Removing Entity ({0}) at {1}, {2}, {3} since it was non-persistent.", id, x, y, z);
  						}
  					}
  					else
  					{
  						if (! options.moddedMap)
  						{
  							anvilCleaner.log("Entity ({0}) at {1}, {2}, {3} was in the wrong type. Removing!", id, x, y, z);
  							fixes++;
  						}
  						else
  						{
  							anvilCleaner.log("Entity ({0}) at {1}, {2}, {3} was in an unknown type. Ignoring!", id, x, y, z);
  							entityTags.add(entity);
  						}
  					}
  				}
  			}
  
  			tag.put("Entities", entityTags);
  		}
  		else
  		{
  			tag.put("Entities", data.entities);
  		}
  
  		if (options.tileEntities)
  		{
  			ListTag<CompoundTag> tileEntityTags = new ListTag<CompoundTag>("TileEntities");
  			for (int i = 0; i < data.tileEntities.size(); i++)
  			{
  				CompoundTag tileEntity = data.tileEntities.get(i);
  				int x = tileEntity.getInt("x");
  				int z = tileEntity.getInt("z");
  				int y = tileEntity.getInt("y");
  				String id = tileEntity.getString("id");
  				int[] ids = TileEntityType.getBIDs(id);
  
  				ListTag<CompoundTag> sections = tag.getList("Sections");
  
  				int rx = x - cx * 16;
  