001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package net.tridentsdk.server.world;
019
020import net.tridentsdk.meta.nbt.NBTField;
021import net.tridentsdk.meta.nbt.NBTSerializable;
022import net.tridentsdk.meta.nbt.TagType;
023import net.tridentsdk.util.NibbleArray;
024
025import java.util.Arrays;
026
027public final class ChunkSection implements NBTSerializable {
028    public static final int LENGTH = 4096; // 16^3 (width * height * depth)
029
030    @NBTField(name = "Blocks", type = TagType.BYTE_ARRAY)
031    public byte[] rawTypes = new byte[LENGTH];
032    @NBTField(name = "Add", type = TagType.BYTE_ARRAY)
033    public byte[] add = new byte[LENGTH / 2];
034    @NBTField(name = "Data", type = TagType.BYTE_ARRAY)
035    public byte[] data = new byte[LENGTH / 2];
036    @NBTField(name = "BlockLight", type = TagType.BYTE_ARRAY)
037    public byte[] blockLight = new byte[LENGTH / 2];
038    @NBTField(name = "SkyLight", type = TagType.BYTE_ARRAY)
039    public byte[] skyLight = new byte[LENGTH / 2];
040    @NBTField(name = "Y", type = TagType.BYTE)
041    protected byte y;
042    public char[] types;
043
044    public ChunkSection(byte i) {
045        this.y = i;
046    }
047
048    // Serialization constructor
049    public ChunkSection() {
050    }
051
052    /**
053     * Gets the position in the section array
054     */
055    public byte y() {
056        return y;
057    }
058
059    protected void loadBlocks() {
060        //NibbleArray add = new NibbleArray(this.add);
061        //NibbleArray data = new NibbleArray(this.data);
062        
063        // DEBUG ===== makes the entire chunk completely lit, not ideal for production
064        Arrays.fill(skyLight, (byte) 255);
065        // =====
066
067        types = new char[rawTypes.length];
068
069        for (int i = 0; i < LENGTH; i += 1) {
070            byte b;
071            byte bData;
072            int bAdd;
073
074            /* Get block data; use extras accordingly */
075            b = rawTypes[i];
076            bAdd = NibbleArray.get(this.add, i) << 12;
077            bData = NibbleArray.get(this.data, i);
078
079            types[i] = (char) (bAdd | ((b & 0xff) << 4) | bData);
080        }
081    }
082
083    protected void updateRaw() {
084        updateRaw(types);
085    }
086
087    protected void updateRaw(char[] data) {
088        if(data.length != LENGTH)
089            throw new IllegalArgumentException("Data length must be 4096!");
090
091        for (int i = 0; i < LENGTH; i++) {
092            rawTypes[i] = (byte) ((data[i] >> 4) & 0xFF);
093            NibbleArray.set(this.data, i, (byte) (data[i] & 0xf));
094            NibbleArray.set(this.add, i, (byte) (data[i] >> 12));
095        }
096    }
097
098    protected void setBlocks(char[] data) {
099        this.types = data;
100    }
101
102    protected void setData(byte[] data) {
103        this.data = data;
104    }
105
106    public char[] types() {
107        return types;
108    }
109}