com.foudroyantfactotum.tool.structure.utility.StructureDefinitionBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.foudroyantfactotum.tool.structure.utility.StructureDefinitionBuilder.java

Source

/*
 * Copyright (c) 2016 Foudroyant Factotum
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, see <http://www.gnu.org/licenses>.
 */
package com.foudroyantfactotum.tool.structure.utility;

import com.foudroyantfactotum.tool.structure.IStructure.IPartBlockState;
import com.foudroyantfactotum.tool.structure.coordinates.BlockPosUtil;
import com.foudroyantfactotum.tool.structure.registry.StructureDefinition;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockPos.MutableBlockPos;

import java.util.BitSet;

import static com.google.common.base.Preconditions.checkNotNull;

public final class StructureDefinitionBuilder {
    private BitSet sbLayout;
    private BlockPos sbLayoutSize;

    private BlockPos masterPosition;
    private BlockPos toolFormPosition;

    private IPartBlockState[][][] states;
    private float[][] collisionBoxes;

    public StructureDefinition build() {
        if (conBlocks == null) {
            throw new StructureDefinitionError("Missing block states");
        }

        //blocks jagged map test
        for (final IBlockState[][] b : conBlocks) {
            if (b.length != conBlocks[0].length) {
                throw new StructureDefinitionError("Construction map jagged");
            }

            for (final IBlockState[] bb : b) {
                if (bb.length != b[0].length) {
                    throw new StructureDefinitionError("Construction map jagged");
                }
            }
        }

        //state jagged map test
        if (state != null) {
            for (final String[][] s : state) {
                if (s.length != state[0].length) {
                    throw new StructureDefinitionError("Construction map jagged");
                }

                for (final String[] ss : s) {
                    if (ss.length != s[0].length) {
                        throw new StructureDefinitionError("Construction map jagged");
                    }
                }
            }

            if (!(conBlocks.length == state.length && conBlocks[0].length == state[0].length
                    && conBlocks[0][0].length == state[0][0].length))
                throw new StructureDefinitionError("block/state sizing mismatch");
        }

        if (toolFormPosition == null) {
            throw new StructureDefinitionError("tool form location missing");
        }

        //-------------------------------------------------------
        //Correct data and align it to the inner data structures.
        //-------------------------------------------------------
        final int xsz = conBlocks.length;
        final int ysz = conBlocks[0].length;
        final int zsz = conBlocks[0][0].length;

        states = new IPartBlockState[xsz][ysz][zsz];

        for (final MutableBlockPos local : BlockPos.getAllInBoxMutable(BlockPos.ORIGIN,
                new BlockPos(xsz - 1, ysz - 1, zsz - 1))) {
            states[local.getX()][local.getY()][local.getZ()] = getBlockState(local);
        }

        //correct collision bounds.
        for (float[] bb : collisionBoxes) {
            bb[0] -= masterPosition.getX();
            bb[3] -= masterPosition.getX();
            bb[1] -= masterPosition.getY();
            bb[4] -= masterPosition.getY();
            bb[2] -= masterPosition.getZ();
            bb[5] -= masterPosition.getZ();
        }

        //correct tool form location
        toolFormPosition = toolFormPosition.subtract(masterPosition);

        return new StructureDefinition(sbLayout, sbLayoutSize, masterPosition, toolFormPosition, states,
                collisionBoxes);
    }

    /**
     * Gets the clean error checked block state
     * @param local local coords of the block within the map
     * @return block state
     */
    private IPartBlockState getBlockState(MutableBlockPos local) {
        final IBlockState block = conBlocks[local.getX()][local.getY()][local.getZ()];

        if (block == null)
            return PartBlockState.of();
        if (state == null)
            return PartBlockState.of(block);

        final String blockState = state[local.getX()][local.getY()][local.getZ()];

        if (blockState == null)
            return PartBlockState.of(block);

        return PartBlockState.of(block, blockState);
    }

    private ImmutableMap<Character, IBlockState> conDef = ImmutableMap.of();
    private IBlockState[][][] conBlocks;

    /**
     * Define what each character represents within the block map
     * @param representation char to unlocal.getZ()ed block name map
     * @exception NullPointerException thrown if block doesn't exist.
     */
    public void assignConstructionDef(ImmutableMap<Character, String> representation) {
        Builder<Character, IBlockState> builder = ImmutableMap.builder();

        for (final Character c : representation.keySet()) {
            final String blockName = representation.get(c);
            final Block block = Block.getBlockFromName(blockName);

            checkNotNull(block, "assignConstructionDef.Block does not exist " + blockName);

            builder.put(c, block.getDefaultState());
        }

        //default
        builder.put(' ', Blocks.AIR.getDefaultState());

        conDef = builder.build();
    }

    /**
     * builds the block array using the representation map and the layout(String[]...)
     * String = x-line
     * String[] = z-line
     * String[]... = y-line
     * @param layer the layout of the blocks.
     * @exception NullPointerException the layout is missing a map
     */
    public void assignConstructionBlocks(String[]... layer) {
        final int xsz = layer[0][0].length();
        final int ysz = layer.length;
        final int zsz = layer[0].length;

        conBlocks = new IBlockState[xsz][ysz][zsz];

        for (final MutableBlockPos local : BlockPos.getAllInBoxMutable(BlockPos.ORIGIN,
                new BlockPos(xsz - 1, ysz - 1, zsz - 1))) {
            final char c = layer[local.getY()][local.getZ()].charAt(local.getX());

            if (!conDef.containsKey(c) && c != '-') {
                throw new StructureDefinitionError("Map missing '" + c + "' @" + local);
            }

            conBlocks[local.getX()][local.getY()][local.getZ()] = c == '-' ? null : conDef.get(c);
        }
    }

    /**
     * Configures the location of the blocks.
     * M => Master block location. Specify only once
     * - => Block position
     *   => No block
     *
     * @param shift translation of S(C).origin to S(F).origin
     * @param layer
     */
    public void setConfiguration(BlockPos shift, String[]... layer) {
        final int xsz = layer[0][0].length();
        final int ysz = layer.length;
        final int zsz = layer[0].length;

        sbLayoutSize = BlockPosUtil.of(xsz, ysz, zsz);
        sbLayout = new BitSet(xsz * ysz * zsz);

        for (final MutableBlockPos local : BlockPos.getAllInBoxMutable(BlockPos.ORIGIN,
                new BlockPos(xsz - 1, ysz - 1, zsz - 1))) {
            final char c = Character.toUpperCase(layer[local.getY()][local.getZ()].charAt(local.getX()));

            switch (c) {
            case 'M': // Master block location
                if (masterPosition == null) {
                    masterPosition = BlockPosUtil.of(local.getX() + shift.getX(), local.getY() + shift.getY(),
                            local.getZ() + shift.getZ());
                } else {
                    throw new StructureDefinitionError("setConfiguration.Master position defined more then once.");
                }

            case ' ':
            case '-':
                sbLayout.set(local.getX() + local.getZ() * xsz + local.getY() * zsz * xsz, c != ' ');
                break;
            default: {
                throw new StructureDefinitionError("setConfiguration.Unknown char '" + c + '\'');
            }
            }
        }

        if (masterPosition == null) {
            throw new StructureDefinitionError("setConfiguration.Master position not defined");
        }
    }

    private ImmutableMap<Character, String> repState = ImmutableMap.of();
    private String[][][] state;

    /**
     * Define what each character represents within the state map
     * @param representation char to "equivelent json" state map
     * @exception NullPointerException thrown if block doesn't exist.
     */
    public void assignConstructionStateDef(ImmutableMap<Character, String> representation) {
        repState = representation;
    }

    /**
     * builds the state array using the representation map and the layout(String[]...)
     * String = x-line
     * String[] = z-line
     * String[]... = y-line
     * @param layer the layout of the states.
     * @exception NullPointerException the layout is missing a map
     */
    public void assignConstructionStateBlocks(String[]... layer) {
        final int xsz = layer[0][0].length();
        final int ysz = layer.length;
        final int zsz = layer[0].length;

        state = new String[xsz][ysz][zsz];

        for (final MutableBlockPos local : BlockPos.getAllInBoxMutable(BlockPos.ORIGIN,
                new BlockPos(xsz - 1, ysz - 1, zsz - 1))) {
            final char c = layer[local.getY()][local.getZ()].charAt(local.getX());

            if (!repState.containsKey(c) && c != ' ') {
                throw new StructureDefinitionError("Map missing '" + c + "' @" + local);
            }

            state[local.getX()][local.getY()][local.getZ()] = repState.get(c);
        }
    }

    public void assignToolFormPosition(BlockPos toolFormPosition) {
        this.toolFormPosition = toolFormPosition;
    }

    /**
     * set collision boxes of structure
     * @param collisionBoxes arrays of collision. must have a length of 6 l=lower left back u=upper right front [lx, ly, lz, ux, uy, uz]
     */
    public void setCollisionBoxes(float[]... collisionBoxes) {
        this.collisionBoxes = collisionBoxes;
    }

    public static class StructureDefinitionError extends Error {
        public StructureDefinitionError(String msg) {
            super(msg);
        }
    }
}