package net.CyanWool.io;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import net.CyanWool.api.CyanWool;
import net.CyanWool.api.io.ChunkIOService;
import net.CyanWool.api.io.RegionFile;
import net.CyanWool.api.world.Chunk;
import net.CyanWool.api.world.World;
import net.CyanWool.world.CyanChunk;
import net.CyanWool.world.Section;
import org.spacehq.mc.protocol.data.game.NibbleArray3d;
import org.spacehq.mc.protocol.data.game.ShortArray3d;
import org.spacehq.opennbt.NBTIO;
import org.spacehq.opennbt.tag.builtin.ByteArrayTag;
import org.spacehq.opennbt.tag.builtin.ByteTag;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import org.spacehq.opennbt.tag.builtin.ListTag;
import org.spacehq.opennbt.tag.builtin.Tag;
public class CyanChunkIOService implements ChunkIOService {
private final World world;
private final File dir;
public CyanChunkIOService(World world) {
this.world = world;
this.dir = new File(world.getPath());
}
@Override
public Chunk readChunk(int x, int z) {
CyanChunk chunk = new CyanChunk(world, x, z);
chunk.setNeedGenerate(true); // TODO
Section sectionsChunk[] = new Section[16];
// Preview loading
for (int i = 0; i < 16; i++) {
byte[] blockLight = new byte[16 * 16 * 16];
byte[] skyLight = new byte[16 * 16 * 16];
ShortArray3d block = new ShortArray3d(4096);
Section section = new Section(i, block, new NibbleArray3d(blockLight), new NibbleArray3d(skyLight));
sectionsChunk[i] = section;
}
RegionFile region = RegionFileCache.getRegionFile(dir, x, z);
int regionX = x & 31;
int regionZ = z & 31;
if (!region.hasChunk(regionX, regionZ)) {
chunk.initializeSections(sectionsChunk);
// TODO: Entity, biomes and etc.
chunk.setLoaded(true);
return chunk; // TODO: maybe ?
}
DataInputStream in = region.getChunkDataInputStream(regionX, regionZ);
CompoundTag compoundTag = null;
try {
compoundTag = (CompoundTag) NBTIO.readTag(in);
} catch (IOException e) {
e.printStackTrace();
}
if (compoundTag == null) {
CyanWool.getLogger().info("null compoundTag");
return chunk;
}
CompoundTag level = compoundTag.get("Level");
ListTag sections = level.get("Sections");
ByteArrayTag biomes = level.get("Biomes");
for (int i = 0; i < sections.size(); i++) {
CompoundTag chunkz = sections.get(i);
ByteArrayTag blocks = chunkz.get("Blocks");
ByteArrayTag blockLight = chunkz.get("BlockLight");
ByteArrayTag skyLight = chunkz.get("SkyLight");
ByteArrayTag data = chunkz.get("Data");
ByteArrayTag add = chunkz.get("Add");
ShortArray3d block = new ShortArray3d(4096);
for (int cX = 0; cX < 16; cX++) {
for (int cY = 0; cY < 16; cY++) {
for (int cZ = 0; cZ < 16; cZ++) {
int index = 256 * cY + 16 * cZ + cX;
int id = blocks.getValue(index) + (add != null ? getValue(add, index) << 8 : 0);
block.setBlockAndData(cX, cY, cZ, id + (id < 0 ? 256 : 0), getValue(data, index));
}
}
}
Section section = new Section(i, block, new NibbleArray3d(blockLight.getValue()), new NibbleArray3d(skyLight.getValue()));
sectionsChunk[i] = section;
}
chunk.initializeSections(sectionsChunk);
// TODO: Entity, biomes and etc.
chunk.setNeedGenerate(false);
chunk.setLoaded(true);
return chunk;
}
private int getValue(ByteArrayTag array, int index) {
return (index % 2 == 0 ? array.getValue(index / 2) : array.getValue(index / 2) >> 4) & 0x0F;
}
@Override
public void saveChunk(Chunk chunk) {
int x = chunk.getX(), z = chunk.getZ();
RegionFile region = RegionFileCache.getRegionFile(dir, x, z);
int regionX = x & (32 - 1);
int regionZ = z & (32 - 1);
DataOutputStream out = region.getChunkDataOutputStream(regionX, regionZ);
DataInputStream in = region.getChunkDataInputStream(regionX, regionZ);
if (in != null && out != null) {
CompoundTag compoundTag = null;
try {
compoundTag = (CompoundTag) NBTIO.readTag(in);
} catch (IOException e) {
e.printStackTrace();
}
if (compoundTag == null)
return;
CompoundTag level = compoundTag.get("Level");
ListTag sections = level.get("Sections");
CyanChunk c = (CyanChunk) chunk;
org.spacehq.mc.protocol.data.game.Chunk[] chunks = c.getSections();
Map<String, Tag> values = compoundTag.getValue();
Map<String, Tag> levelInfo = level.getValue();
ArrayList<Tag> newSections = new ArrayList<Tag>();
for (int i = 0; i < sections.size(); i++) {
CompoundTag chunkz = sections.get(i);
Map<String, Tag> cv = chunkz.getValue();
ByteTag y = chunkz.get("Y");
ByteArrayTag blocks = chunkz.get("Blocks");
ByteArrayTag blockLight = chunkz.get("BlockLight");
ByteArrayTag skyLight = chunkz.get("SkyLight");
ByteArrayTag data = chunkz.get("Data");
// ByteArrayTag add = chunkz.get("Add");
if (chunks[i] != null) {
if (chunks[i].getBlockLight() != null)
blockLight.setValue(chunks[i].getBlockLight().getData());
if (chunks[i].getSkyLight() != null)
skyLight.setValue(chunks[i].getSkyLight().getData());
if (chunks[i].getBlocks() != null)
for (int cX = 0; cX < 16; cX++)
for (int cY = 0; cY < 16; cY++)
for (int cZ = 0; cZ < 16; cZ++) {
int index = 256 * cY + 16 * cZ + cX;
int id = chunks[i].getBlocks().getBlock(cX, cY, cZ);
if (id > 128)
id -= 256;
blocks.setValue(index, Byte.parseByte(id + ""));
if (index % 2 == 0)
data.setValue(index / 2, (byte) ((getValue(data, index + 1) << 4) | chunks[i].getBlocks().getData(cX, cY, cZ)));
else data.setValue(index / 2, (byte) ((chunks[i].getBlocks().getData(cX, cY, cZ) << 4) | getValue(data, index - 1)));
}
}
cv.put("Y", y);
cv.put("Blocks", blocks);
cv.put("BlockLight", blockLight);
cv.put("SkyLight", skyLight);
cv.put("Data", data);
// cv.put("Add", add);//How to calculate from value if even
// needed
chunkz.setValue(cv);
newSections.add(chunkz);
}
sections.setValue(newSections);
levelInfo.put("Sections", sections);
level.setValue(levelInfo);
values.put("Level", level);
compoundTag.setValue(values);
try {
NBTIO.writeTag(out, compoundTag);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}