import * as I from 'immutable'; import {compose, EventEmitter} from '@avocado/core'; import {Rectangle, Vector} from '@avocado/math'; import {TileUpdatePacket} from './packets/tile-update.packet'; const CHUNK_AXIS = 10; const decorate = compose( EventEmitter, Vector.Mixin('size', 'width', 'height', { default: [0, 0], }), ); export class Tiles extends decorate(class {}) { constructor(json) { super(); // this.chunks = []; this.data = []; if ('undefined' !== typeof json) { this.fromJSON(json); } } acceptPacket(packet) { // if (packet instanceof TileUpdatePacket) { // const unpackedPosition = [ // packet.data.position & 0xFFFF, // packet.data.position >> 16, // ]; // this.setTileAt(unpackedPosition, packet.data.tile); // } } // chunkIndexAtPosition(position) { // const chunkCount = Vector.ceil(Vector.scale(this.size, 1 / CHUNK_AXIS)); // const chunkPosition = Vector.floor(Vector.scale(position, 1 / CHUNK_AXIS)); // const chunkIndex = chunkPosition[1] * chunkCount[0] + chunkPosition[0]; // return chunkIndex; // } // static createChunkFromData(position, size, data) { // const chunk = Array(CHUNK_AXIS * CHUNK_AXIS).fill(0); // let chunkIndex = 0; // const chunkPosition = Vector.scale(position, CHUNK_AXIS); // let dataIndex = size[0] * chunkPosition[1] + chunkPosition[0]; // for (let y = 0; y < CHUNK_AXIS; ++y) { // for (let x = 0; x < CHUNK_AXIS; ++x) { // if (chunkPosition[0] < size[0] && chunkPosition[1] < size[1]) { // chunk[chunkIndex] = data[dataIndex]; // } // chunkIndex += 1; // chunkPosition[0] += 1; // dataIndex += 1; // } // chunkPosition[0] -= CHUNK_AXIS; // chunkPosition[1] += 1; // dataIndex -= CHUNK_AXIS; // dataIndex += size[0]; // } // return chunk; // } // forEachTile(fn) { // let [x, y] = [0, 0]; // let [width, height] = this.size; // let i = 0; // for (let k = 0; k < height; ++k) { // for (let j = 0; j < width; ++j) { // fn(this.data[i], x, y, i); // ++i; // ++x; // } // x = 0; // ++y; // } // } fromJSON(json) { if (json.size) { super.size = json.size; } // this.chunks = []; // const chunkCount = Vector.ceil(Vector.scale(this.size, 1 / CHUNK_AXIS)); // if (json.data && json.data.length > 0) { // for (let y = 0; y < chunkCount[1]; ++y) { // for (let x = 0; x < chunkCount[0]; ++x) { // this.chunks.push(Tiles.createChunkFromData( // [x, y], // this.size, // json.data // )); // } // } // } // if (json.chunks && json.chunks.length > 0) { // } if (json.data && json.data.length > 0) { this.data = json.data.slice(0); } // Instantiate blank tiles if we got size but no data. else { this.data = Array(Vector.area(this.size)).fill(0); } return this; } // indexAt(position) { // return this.width * position[1] + position[0]; // } // packetsForUpdate() { // const packetsForUpdate = this.updatePackets; // this.updatePackets = []; // return packetsForUpdate; // } get rectangle() { return Rectangle.compose([0, 0], this.size); } setTileAt(position, tile) { const oldTile = this.tileAt(position); if (oldTile === tile) { return; } const index = position[1] * this.width + position[0]; if (index < 0 || index >= this.data.length) { return; } this.data[index] = tile; const packedPosition = position[1] << 16 | position[0]; // this.updatePackets.push(new TileUpdatePacket({ // position: packedPosition, // tile, // })); this.emit('dataChanged'); } get size() { return super.size; } set size(size) { super.size = size; // const newChunks = []; // const chunkCount = Vector.ceil(Vector.div(size, [CHUNK_AXIS, CHUNK_AXIS])); // const chunkLinearCount = Vector.area(chunkCount); // for (let i = 0; i < chunkLinearCount; ++i) { // newChunks. // } // for (let y = 0; y < chunkCount[1]; y++) { // for (let x = 0; x < chunkCount[0]; x++) { // newChunks[y][x] // } // } } slice(rectangle) { const tilesRectangle = this.rectangle; // Get intersection. if (!Rectangle.intersects(rectangle, tilesRectangle)) { return []; } let [x, y, sliceWidth, sliceHeight] = Rectangle.intersection( rectangle, tilesRectangle, ); // No muls in the loop. let sliceRow = y * sliceWidth; const dataWidth = this.width; let dataRow = y * dataWidth; // Copy slice. const slice = new Array(sliceWidth * sliceHeight); for (let j = 0; j < sliceHeight; ++j) { for (let i = 0; i < sliceWidth; ++i) { slice[sliceRow + x] = this.data[dataRow + x]; x++; } sliceRow += sliceWidth; dataRow += dataWidth; x -= sliceWidth; } return slice; } tileAt(position) { const index = this.indexAt(position); if (index < 0 || index >= this.data.length) { return; } return this.data[index]; } toJSON() { return { size: this.size, data: this.data, }; } toNetwork(informed) { return { size: this.size, data: this.data, }; } }