<commit_before>/*
 * Copyright 2014 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package uk.co.thinkofdeath.mapviewer.worker.world;

import com.google.gwt.core.client.JsArrayInteger;
import elemental.html.ArrayBuffer;
import uk.co.thinkofdeath.mapviewer.shared.block.Block;
import uk.co.thinkofdeath.mapviewer.shared.block.Blocks;
import uk.co.thinkofdeath.mapviewer.shared.building.ModelBuilder;
import uk.co.thinkofdeath.mapviewer.shared.model.Model;
import uk.co.thinkofdeath.mapviewer.shared.support.DataReader;
import uk.co.thinkofdeath.mapviewer.shared.support.TUint8Array;
import uk.co.thinkofdeath.mapviewer.shared.worker.ChunkBuildReply;
import uk.co.thinkofdeath.mapviewer.shared.worker.ChunkLoadedMessage;
import uk.co.thinkofdeath.mapviewer.shared.worker.WorkerMessage;
import uk.co.thinkofdeath.mapviewer.shared.world.Chunk;
import uk.co.thinkofdeath.mapviewer.shared.world.ChunkSection;
import uk.co.thinkofdeath.mapviewer.worker.Worker;

import java.util.Map;

public class WorkerChunk extends Chunk {

    private final WorkerWorld world;

    /**
     * Creates a chunk at the passed position
     *
     * @param x
     *         The x position
     * @param z
     *         The z position
     */
    public WorkerChunk(WorkerWorld world, int x, int z, ArrayBuffer data, boolean reply) {
        super(world, x, z);
        this.world = world;

        TUint8Array byteData = TUint8Array.create(data, 0, data.getByteLength());
        DataReader dataReader = DataReader.create(data);

        // TODO: Rewrite chunk format

        // First 8 bytes are two ints (x, z)
        // but since we already know which chunk
        // we requested we can ignore them

        // Bit mask of what sections actually exist in the chunk
        int sectionMask = dataReader.getUint16(8);

        // Current offset into the buffer
        int offset = 10;

        for (int i = 0; i < 16; i++) {
            if ((sectionMask & (1 << i)) == 0) {
                continue;
            }
            ChunkSection chunkSection = sections[i] = new ChunkSection();
            int idx = 0;
            for (int oy = 0; oy < 16; oy++) {
                for (int oz = 0; oz < 16; oz++) {
                    for (int ox = 0; ox < 16; ox++) {
                        int id = dataReader.getUint16(offset);
                        int dataVal = byteData.get(offset + 2);
                        int light = byteData.get(offset + 3);
                        int sky = byteData.get(offset + 4);
                        offset += 5;

                        Block block = world.getMapViewer().getBlockRegistry().get(id, dataVal);
                        if (block == null) {
                            block = Blocks.MISSING_BLOCK;
                        }

                        if (!blockIdMap.containsKey(block)) {
                            idBlockMap.put(nextId, block);
                            blockIdMap.put(block, nextId);
                            nextId++;
                        }
                        int chunkBlockId = blockIdMap.get(block);

                        chunkSection.getBlocks().set(idx, chunkBlockId);
                        chunkSection.getBlockLight().set(idx, light);
                        chunkSection.getSkyLight().set(idx, sky);
                        idx++;

                        if (block != Blocks.AIR) {
                            chunkSection.increaseCount();
                        }
                        if (light != 0) {
                            chunkSection.increaseCount();
                        }
                        if (sky != 15) {
                            chunkSection.increaseCount();
                        }
                    }
                }
            }
        }
        if (reply) {
            sendChunk();
        } else {
            ((Worker) world.getMapViewer()).postMessage(WorkerMessage.create("null", null, false));
        }
    }

    // Sends the chunk back to the requester
    private void sendChunk() {
        ChunkLoadedMessage message = ChunkLoadedMessage.create(getX(), getZ());

        // Copy sections
        for (int i = 0; i < 16; i++) {
            if (sections[i] != null) {
                message.setSection(i, sections[i].getCount(), sections[i].getBuffer());
            }
        }

        message.setNextId(nextId);

        JsArrayInteger keys = idBlockMap.keys();
        for (int i = 0; i < keys.length(); i++) {
            int key = keys.get(i);
            message.addIdBlockMapping(key, idBlockMap.get(key));
        }

        for (Map.Entry<Block, Integer> e : blockIdMap.entrySet()) {
            message.addBlockIdMapping(e.getKey(), e.getValue());
        }

        ((Worker) world.getMapViewer()).postMessage(WorkerMessage.create("chunk:loaded", message, false));
    }

    /**
     * Builds the chunk section for rendering and sends it back to the client
     *
     * @param sectionNumber
     *         The section number of build
     * @param buildNumber
     *         The id for this build
     */
    public void build(int sectionNumber, int buildNumber) {
        //TODO: Handle transparent blocks
        ModelBuilder builder = new ModelBuilder();
        for (int y = 0; y < 16; y++) {
            for (int z = 0; z < 16; z++) {
                for (int x = 0; x < 16; x++) {
                    Block block = getBlock(x, (sectionNumber << 4) + y, z);
                    if (block.isRenderable()) {<commit_msg>Manually copy section data instead of letting the browser do it.<commit_after>/*
 * Copyright 2014 <NAME>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package uk.co.thinkofdeath.mapviewer.worker.world;

import com.google.gwt.core.client.JsArrayInteger;
import elemental.html.ArrayBuffer;
import uk.co.thinkofdeath.mapviewer.shared.block.Block;
import uk.co.thinkofdeath.mapviewer.shared.block.Blocks;
import uk.co.thinkofdeath.mapviewer.shared.building.ModelBuilder;
import uk.co.thinkofdeath.mapviewer.shared.model.Model;
import uk.co.thinkofdeath.mapviewer.shared.support.DataReader;
import uk.co.thinkofdeath.mapviewer.shared.support.TUint8Array;
import uk.co.thinkofdeath.mapviewer.shared.worker.ChunkBuildReply;
import uk.co.thinkofdeath.mapviewer.shared.worker.ChunkLoadedMessage;
import uk.co.thinkofdeath.mapviewer.shared.worker.WorkerMessage;
import uk.co.thinkofdeath.mapviewer.shared.world.Chunk;
import uk.co.thinkofdeath.mapviewer.shared.world.ChunkSection;
import uk.co.thinkofdeath.mapviewer.worker.Worker;

import java.util.ArrayList;
import java.util.Map;

public class WorkerChunk extends Chunk {

    private final WorkerWorld world;

    /**
     * Creates a chunk at the passed position
     *
     * @param x
     *         The x position
     * @param z
     *         The z position
     */
    public WorkerChunk(WorkerWorld world, int x, int z, ArrayBuffer data, boolean reply) {
        super(world, x, z);
        this.world = world;

        TUint8Array byteData = TUint8Array.create(data, 0, data.getByteLength());
        DataReader dataReader = DataReader.create(data);

        // TODO: Rewrite chunk format

        // First 8 bytes are two ints (x, z)
        // but since we already know which chunk
        // we requested we can ignore them

        // Bit mask of what sections actually exist in the chunk
        int sectionMask = dataReader.getUint16(8);

        // Current offset into the buffer
        int offset = 10;

        for (int i = 0; i < 16; i++) {
            if ((sectionMask & (1 << i)) == 0) {
                continue;
            }
            ChunkSection chunkSection = sections[i] = new ChunkSection();
            int idx = 0;
            for (int oy = 0; oy < 16; oy++) {
                for (int oz = 0; oz < 16; oz++) {
                    for (int ox = 0; ox < 16; ox++) {
                        int id = dataReader.getUint16(offset);
                        int dataVal = byteData.get(offset + 2);
                        int light = byteData.get(offset + 3);
                        int sky = byteData.get(offset + 4);
                        offset += 5;

                        Block block = world.getMapViewer().getBlockRegistry().get(id, dataVal);
                        if (block == null) {
                            block = Blocks.MISSING_BLOCK;
                        }

                        if (!blockIdMap.containsKey(block)) {
                            idBlockMap.put(nextId, block);
                            blockIdMap.put(block, nextId);
                            nextId++;
                        }
                        int chunkBlockId = blockIdMap.get(block);

                        chunkSection.getBlocks().set(idx, chunkBlockId);
                        chunkSection.getBlockLight().set(idx, light);
                        chunkSection.getSkyLight().set(idx, sky);
                        idx++;

                        if (block != Blocks.AIR) {
                            chunkSection.increaseCount();
                        }
                        if (light != 0) {
                            chunkSection.increaseCount();
                        }
                        if (sky != 15) {
                            chunkSection.increaseCount();
                        }
                    }
                }
            }
        }
        if (reply) {
            sendChunk();
        } else {
            ((Worker) world.getMapViewer()).postMessage(WorkerMessage.create("null", null, false));
        }
    }

    // Sends the chunk back to the requester
    private void sendChunk() {
        ChunkLoadedMessage message = ChunkLoadedMessage.create(getX(), getZ());
        ArrayList<Object> buffers = new ArrayList<>();
        // Copy sections
        for (int i = 0; i < 16; i++) {
            if (sections[i] != null) {
                TUint8Array data = TUint8Array.create(sections[i].getBuffer());
                buffers.add(data.getBuffer());
                message.setSection(i, sections[i].getCount(), data);
            }
        }

        message.setNextId(nextId);

        JsArrayInteger keys = idBlockMap.keys();
        for (int i = 0; i < keys.length(); i++) {
            int key = keys.get(i);
            message.addIdBlockMapping(key, idBlockMap.get(key));
        }

        for (Map.Entry<Block, Integer> e : blockIdMap.entrySet()) {
            message.addBlockIdMapping(e.getKey(), e.getValue());
        }

        ((Worker) world.getMapViewer()).postMessage(
                WorkerMessage.create("chunk:loaded", message, false),
                buffers.toArray(new Object[buffers.size()]));
    }

    /**
     * Builds the chunk section for rendering and sends it back to the client
     *
     * @param sectionNumber
     *         The section number of build
     * @param buildNumber
     *         The id for this build
     */
    public void build(int sectionNumber, int buildNumber) {
        //TODO: Handle transparent blocks
        ModelBuilder builder = new ModelBuilder();
        for (int y = 0; y < 16; y++) {
            for (int z = 0; z < 16; z++) {
                for (int x = 0; x < 16; x++) {
                    Block block = getBlock(x, (sectionNumber << 4) + y, z);
                    if (block.isRenderable()) {
{'fraction_non_alphanumeric': 0.10572937830150346, 'fraction_numerical': 0.009264526615197074, 'mean_word_length': 1.7328447701532312, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6746759', 'n_tokens_mistral': 3479, 'n_tokens_neox': 3242, 'n_words': 907}