World.js

/**
 * @module core/World
 * @description A World can save the state of any voxels added to it
 * @requires core/Voxel
 * @requires core/Mesh
**/
'use strict';

const {assign} = Object;
const Mesh     = require('./Mesh');
const Voxel    = require('./Voxel');

module.exports = World;

/**
 * @name World
 * @constructor
 * @param {module:core/Scene~Scene} scene Scene to create world with
 * @param {string} label String to be used as key id when saving world to localStorage
 * @example <caption>Add a scene to a world</caption>
 * const Voxelcss = require('voxelcss');
 * let scene = new Voxelcss.Scene();
 * let world = new Voxelcss.World(scene);
**/
function World(scene, label) {
    if (scene === undefined) {
        throw 'World cannot be instantiated without a Scene instance';
    }
    let voxels = [];
    let worldLabel = label || '*';
    let getScene = () => scene;
    let getVoxels = () => voxels;
    let formSaveName = () => `savedWorld<${worldLabel}>`;
    assign(this, {
        add,
        remove,
        clear,
        getScene,
        getVoxels,
        import: importVoxel,
        export: exportVoxel,
        load: () => importVoxel(localStorage.getItem(formSaveName()) || '[]'),
        isSaved: () => !!localStorage.getItem(formSaveName()),
        save: () => localStorage.setItem(formSaveName(), exportVoxel()),
        deleteSave: () => localStorage.setItem(formSaveName(), '')
    });
    function add(voxel) {
        voxels.push(voxel);
        return scene.add(voxel);
    }
    function remove(voxel) {
        let index = voxels.indexOf(voxel);
        let canRemove = (index > -1);
        if (canRemove) {
            scene.remove(voxel);
            voxels.splice(index, 1);
        }
        return canRemove;
    }
    function clear() {
        while (voxels.length > 0) {remove(voxels[0]);}
    }
    function exportVoxel() {
        return JSON.stringify(voxels.map(voxel => getData(voxel)));
    }
    function importVoxel(serializedData) {
        if (typeof serializedData === 'string') {
            try {
                clear();
                JSON.parse(serializedData).forEach(obj => {
                    let {dimension, mesh, position} = obj;
                    let {x, y, z} = position;
                    var voxel = new Voxel([x, y, z], dimension);
                    voxel.setMesh(Mesh.loadFromSerial(mesh));
                    add(voxel);
                });
            } catch (e) {
                throw 'Cannot import voxel data';
            }
        } else {
            throw 'Only serialized data can be imported';
        }
    }
    function getData(voxel) {
        return {
            position: voxel.getPosition(),
            dimension: voxel.getDimension(),
            mesh: voxel.getMesh().serialize()
        };
    }
}