package net.knarcraft.stargate.portal; import net.knarcraft.stargate.container.RelativeBlockVector; import java.io.BufferedWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * The gate layout describes where every part of the gate should be * *

The gate layout parses a layout described by a Character matrix and stores the different parts of the gate as * relative block vectors. All relative vectors has an origin in the top-left block when looking at the gate's front * (the side with the sign)

*/ public class GateLayout { private final Character[][] layout; private final List exits = new ArrayList<>(); private RelativeBlockVector[] entrances = new RelativeBlockVector[0]; private RelativeBlockVector[] border = new RelativeBlockVector[0]; private RelativeBlockVector[] controls = new RelativeBlockVector[0]; private RelativeBlockVector exitBlock = null; /** * Instantiates a new gate layout * * @param layout

A character array describing the layout

*/ public GateLayout(Character[][] layout) { this.layout = layout; readLayout(); } /** * Gets two of the corners of the gate layout creating the smallest box the gate can be contained within * * @return

Two of the gate's corners

*/ public RelativeBlockVector[] getCorners() { return new RelativeBlockVector[]{ new RelativeBlockVector(0, 0, 0), new RelativeBlockVector(layout[0].length - 1, layout.length - 1, 1) }; } /** * Gets the character array describing this layout * * @return

The character array describing this layout

*/ public Character[][] getLayout() { return this.layout; } /** * Gets the locations of entrances for this gate * * @return

The locations of entrances for this gate

*/ public RelativeBlockVector[] getEntrances() { return entrances; } /** * Gets the locations of border blocks for the gate described by this layout * *

A border block is basically any block of the frame. In terms of the nether gate, the border blocks are every * block of the gate that's not air when the gate is closed. The sign and button are not border blocks.

* * @return

The locations of border blocks for this gate

*/ public RelativeBlockVector[] getBorder() { return border; } /** * Gets the exit block defined in the layout * * @return

The exit block defined in the layout

*/ public RelativeBlockVector getExit() { return exitBlock; } /** * Gets other possible exits of the gate * * @return

Other possible gate exits

*/ public List getExits() { return exits; } /** * Gets the locations of the control blocks for this gate * *

The control blocks are the blocks where a sign can be placed to create a portal.

* * @return

The locations of the control blocks for this gate

*/ public RelativeBlockVector[] getControls() { return controls; } /** * Saves the gate layout using a buffered writer * * @param bufferedWriter

The buffered writer to write to

* @throws IOException

If unable to write to the buffered writer

*/ public void save(BufferedWriter bufferedWriter) throws IOException { for (Character[] line : this.layout) { for (Character symbol : line) { bufferedWriter.append(symbol); } bufferedWriter.newLine(); } } /** * Reads the gate layout to relative block vectors */ private void readLayout() { List entranceList = new ArrayList<>(); List borderList = new ArrayList<>(); List controlList = new ArrayList<>(); RelativeBlockVector[] relativeExits = new RelativeBlockVector[layout[0].length]; RelativeBlockVector lastExit = null; int[] exitDepths = readLayout(controlList, entranceList, borderList); //Generate other possible exits for (int x = 0; x < exitDepths.length; x++) { relativeExits[x] = new RelativeBlockVector(x, exitDepths[x], 0); } //Add non-null exits to the exits list for (int x = relativeExits.length - 1; x >= 0; x--) { if (relativeExits[x] != null) { lastExit = relativeExits[x]; } else { relativeExits[x] = lastExit; } if (exitDepths[x] > 0) { this.exits.add(relativeExits[x]); } } this.entrances = entranceList.toArray(this.entrances); this.border = borderList.toArray(this.border); this.controls = controlList.toArray(this.controls); } /** * Reads the given layout matrix, filling in the given lists of relative block vectors * * @param controlList

The list of control blocks to save to

* @param entranceList

The list of entrances to save to

* @param borderList

The list of border blocks to save to

* @return

A list of depths of possible extra exits

*/ private int[] readLayout(List controlList, List entranceList, List borderList) { //Store the depth/line of each int[] exitDepths = new int[layout[0].length]; int lineCount = layout.length; for (int lineIndex = 0; lineIndex < lineCount; lineIndex++) { int rowSize = layout[lineIndex].length; for (int rowIndex = 0; rowIndex < rowSize; rowIndex++) { Character key = layout[lineIndex][rowIndex]; parseLayoutCharacter(key, rowIndex, lineIndex, exitDepths, controlList, entranceList, borderList); } } return exitDepths; } /** * Parses one character of the layout * * @param key

The character read

* @param rowIndex

The row of the read character

* @param lineIndex

The line of the read character

* @param exitDepths

The list of exit depths to save to

* @param controlList

The list of control blocks to save to

* @param entranceList

The list of entrances to save to

* @param borderList

The list of border blocks to save to

*/ private void parseLayoutCharacter(Character key, int rowIndex, int lineIndex, int[] exitDepths, List controlList, List entranceList, List borderList) { //Add control blocks if (key.equals(GateHandler.getControlBlockCharacter())) { controlList.add(new RelativeBlockVector(rowIndex, lineIndex, 0)); } if (key.equals(GateHandler.getEntranceCharacter()) || key.equals(GateHandler.getExitCharacter())) { //Register entrances entranceList.add(new RelativeBlockVector(rowIndex, lineIndex, 0)); //Find the lowest exit block at a given x position exitDepths[rowIndex] = lineIndex; //Register exit if (key.equals(GateHandler.getExitCharacter())) { this.exitBlock = new RelativeBlockVector(rowIndex, lineIndex, 0); } } else if (!key.equals(GateHandler.getAnythingCharacter())) { //Add border borderList.add(new RelativeBlockVector(rowIndex, lineIndex, 0)); } } }